home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Text⁄Files / Suntar 1.3.2 / suntar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-31  |  88.4 KB  |  3,212 lines  |  [TEXT/KAHL]

  1. /*******************************************************************************\
  2.  
  3. main module
  4.  
  5. suntar 1.3.2, ©1991-92 Sauro & Gabriele Speranza
  6.  
  7. This program is public domain, feel free to use it or part of it for anything
  8.  
  9. \*******************************************************************************/
  10.  
  11.  
  12. #include "PB_sync.h"
  13. #include "antiglue.h"
  14.  
  15. /*#include    <EventMgr.h>
  16. #include    <QuickDraw.h>
  17. #include    <StdFilePkg.h>
  18. */
  19.  
  20. #ifdef THINK_C_5
  21. #include <packages.h>
  22. #else
  23. #include <IntlPkg.h>
  24. #endif
  25. /*
  26.  
  27. #include    <DiskDvr.h>
  28. #include    <DeviceMgr.h>
  29. */
  30.  
  31. #include <string.h>
  32.  
  33. #include "windows.h"
  34. #include "suntar.h"
  35.  
  36. #define dp printf  /* use it for debug, so it's easy to */
  37.                 /* find&delete all the extra print instructions */
  38.  
  39.  
  40. MenuHandle writeMenu,hackersMenu,tarPopupMenu,ntAPopupMenu;
  41.  
  42. short err_code;
  43. short drive_number=0;
  44.  
  45. options_type options;
  46. long last_selection=0;
  47. short again_command=0;
  48. sector_t sectors_on_floppy;
  49. OSType tar_creator,bar_creator,bar_type;
  50. static Boolean append_mode;
  51. Boolean in_Italia=false;
  52. Boolean ignore_errors=false;
  53. Boolean confirm_saves=false;
  54. Boolean expert_mode=false;
  55. Boolean non_convertire=false;
  56. Boolean disco_espulso;        /* was my disk ejected ? */
  57. Boolean sto_lavorando=false;    /* non usarlo se non per lo scopo attuale, dire al calcolo del
  58.                                 tempo di sleep per WaitNextEvent di ritornare sempre 0, e sapere
  59.                                 se devo abilitare il comando Pause 
  60.                                 -- consider it as a read only variable !*/
  61. static Boolean pausable=false;
  62. unsigned char file_aperto=0;
  63. static unsigned char check_ev_timing;
  64. #ifdef V_122
  65. Boolean smallFilesAreASCII;
  66. #endif
  67.  
  68. short disable_binhex;            /* bit 0: disable conversion
  69.                                    bit 1: show info in extract
  70.                                    bit 2: show info in list
  71.                                    bit 3: save .info */
  72.  
  73. short last_drive,preferred_drive;
  74. short back_prio;
  75.  
  76. struct disk_info di;
  77.  
  78. static Boolean preferences_changed=0;    /* Apple (TN 188) discourages to call 
  79.         ChangedResource if it's not followed immediately by WriteResource, 
  80.         and I want to modify the file only once, and not to modify it if nothing 
  81.         changed */
  82. sector_t settori_passati;
  83.  
  84. enum tipo_fase fase;
  85. short n_superdrives;
  86. sector_t file_current_s;
  87. short drive_type[max_drive];
  88. extern sector_t next_header_for_AIX;
  89. unsigned char window_title[]="\psuntar 1.3.2 - console";
  90. short default_flags =READONLY|CONSOLE|NOCLOSEBOX;
  91. extern short floppy_buffer_size;
  92. extern unsigned short hd_buffer_size;
  93.  
  94.  
  95. void handle_menus(long);
  96. void add_menu(void);
  97. short my_quit_handler(void);
  98. void EnableDisableItem(MenuHandle,short,Boolean);
  99. Boolean list_events(void);
  100. short dialogo_abort(void);
  101.  
  102. static char diskWriteErrMsg[]="Disk write error %d\n";
  103. char DONE[]="Done\n",FINITO[]="Finito\n";
  104. char START_READ[]="Start reading\n";
  105.  
  106.  
  107.  
  108. /***************** main ******************/
  109.  
  110.  
  111. /*
  112. suntar use an architecture which is unusual, at least in the Mac world:
  113. it has not a main event loop.
  114.  When you have passed the first wave of horror and astonishment, I'll
  115. tell you how it works.
  116.  The MainEvent routine calls GetNextEvent and serves the event, but:
  117. 1) it returns to the caller, it does not loop internally
  118. 2) it does not know how to serve all events, since it's part of the
  119.    windows module and does not know anything about the tar/untar modules:
  120.    you must enlarge its capabilities by providing an event filter and an 
  121.    "application specific menus handler", and maybe some "updaters" and
  122.    "activaters" for windows (e.g. other filters)
  123. 3) some menu items (mainly, preferences) are handled immediately, but others only
  124.     set the "last_selection" variable which the caller then examines and handles.
  125.  That is, MainEvent is a relatively low-level routine, which is not allowed to
  126. take important decisions.
  127.  So, suntar has several event loops, which call MainEvent, usually after installing
  128. different event filters. Furthermore, MainEvent is called periodically
  129. while suntar is working, with one further event filter which disables all the
  130. events which are not essential (almost all menu items are disabled during
  131. execution of commands). This architecture may easily emulate a typical Mac
  132. behaviour, but it's more flexible and powerful.
  133.   Finally, MainEvent was broken into two parts, and sometimes one calls
  134. the two parts, doing its own event handling between the two calls, so reducing the
  135. need for a lot of filters.
  136. The result is that the program is organized in a UNIX-like fashion, the
  137. "master", the control center, is the main program, not the event loop. The most notable
  138. difference: rather than calling a "print menu screen & wait for an answer"
  139. suntar sets the "fase" variable (see later) and calls MainEvent in a loop
  140. until the global variable last_selection has a non-zero value.
  141. Other not obvious features in the basic architecture of suntar are:
  142. -) a "fase" (phase) global variable must always tell what suntar is currently
  143.    doing, it's used to control the state of the menus (during work, many 
  144.    items are disabled) and sometimes some minor decisions (e.g. Expert list
  145.    behaves slightly differently from List, but it's executed by the same
  146.    function with the same parameters)
  147. -) background events are controlled from within the lowest level operations, hence
  148.    high level functions cannot avoid to be paused or aborted (through
  149.    a longjmp) nor avoid that the preferences settings be changed: they
  150.    must ensure correct operation even in those situations.
  151.  
  152.  In other words: the body of suntar is written in a UNIX-like fashion: it
  153. believes to be the only one to take decisions, while Mac-like events (updates?
  154. activation of DAs? what are those things?) are left to another module which
  155. conceptually might be another task. But it's NOT another task, hence the UNIX-like
  156. part of suntar must explicitly activate the event module, by calling check_events
  157. (which obviously calls MainEvent).
  158.  Furthermore, on UNIX (or VMS or MS-DOS) a menu selection looks like this:
  159.  
  160. selection=my_menu(3,
  161. "-------------------------\n\
  162. 1  First command\n\
  163. 2  Second command\n\
  164. 3  Last choice\n\
  165. -------------------------\n\
  166. Your choice:");
  167.  
  168. in suntar, one must have a menu resource and modify MaintainApplSpecificMenus
  169. in order to activate/deactivate them properly in the different phases of work
  170. and according to some status variables. Finally, one does this:
  171.  
  172. fase= a phase in which that menu is enabled;
  173. last_selection=0;    / * it should be still 0, but just in case... * /
  174. while(last_selection==0)
  175.     MainEvent();
  176.  
  177. Now last_selection contains the number of the requested command (note that some
  178. menu items are not known to the UNIX-like portion of suntar and are served by
  179. the other module without any report).
  180.  The Mac-aware module is totally responsible for the text windows (windows,
  181. not window: it's a multiwindow system, but suntar exploits only one as the
  182. console). Since its was adapted from a text editor it may conceptually allow
  183. general-purpose text editing, but the UNIX-like portion exploits only its
  184. TTY-like capabilities.
  185.  Anyway, choosing to emulate the most antiquate form of TTY (the one which
  186. printed on paper rather than on a CRT) has given to our module the possibility
  187. to scroll and resize the console window: Symantec in its ANSI library chose
  188. to give more power: modern video terminals have commands to clear the screen or
  189. position the cursor at any position, but in order to implement even only one
  190. such command they were obliged to fix the screen size to 25*80 characters
  191. (you can't position the cursor on the screen it there isn't a coordinate
  192. system on it), with no scroll, a very bad resize and a non-Mac feeling.
  193.  
  194.  So, a student who programmed mostly on UNIX (Sauro) and an engineer with UNIX
  195. and VMS experience (Gabriele) could write a Macintosh application without
  196. being obliged to change their habits. And anyway, this structure is flexible
  197. enough to allow us to write new fully-Mac routines (e.g. the options box) or
  198. to let the UNIX-like module handle some Mac-like events (easy, since there
  199. is no rigid rule about which module must handle which events: add a new event
  200. filter, and the responsibility for handling an event is moved to it).
  201.  
  202. */
  203.  
  204. void main()
  205. {
  206. short command;
  207. short files_to_be_opened;
  208. short last_file_opened=0;
  209.  
  210. /* install the handlers for events which the window module doesn't know how
  211. to handle */
  212. my_handle_menus=handle_menus;
  213. my_add_menus=add_menu;
  214.  
  215. /* initialize everything */
  216. /* l'ordine è importante perché a) ci sono delle dipendenze da variabili
  217.    inizializzate da un'altra di esse, e b) determina dove sono caricate le
  218.    risorse di codice e quindi la frammentazione della memoria */
  219. init_hqx_tab();
  220. InitConsole();
  221. prefs_da_risorsa();
  222. init_hd_buffering();
  223. init_buffering();
  224.  
  225. /* new for suntar 1.3.2: if the user requested to open some files (e.g. by
  226. System 7's drag and drop) then open them */
  227. CountAppFiles(&command,&files_to_be_opened);
  228. if(files_to_be_opened!=0 && command==appPrint){    /* suntar can't print files ! */
  229.     SysBeep(5);
  230.     ExitToShell();
  231.     }
  232.  
  233. /* look at what disk drives and device driver are available */
  234. identifica_hardware();
  235.  
  236. /* install the Quit handler */
  237. my_at_exit= my_quit_handler;
  238.  
  239. /* main loop */
  240.  
  241. /* debugging: open a second window so debugging prints don't mix with the
  242. normal outputs * /
  243. printf("inizio\n");
  244. pStrcpy(window_title,"\pDebug");
  245. new_window();
  246. / * */
  247.  
  248.  
  249. #if 0
  250. {barh_type barh;
  251. printf("offsets = %ld %ld %ld %ld\n",(long)(&tarh.linkflag-tarh.name),
  252. (long)(tarh.linkname-tarh.name),(long)(tarh.offset-tarh.name),(long)(sizeof(tarh)));
  253. printf("offsets = %ld %ld %ld %ld\n",(long)(&barh.linkflag-barh.mode),
  254. (long)(&barh.bar_magic[0]-barh.mode),(long)(barh.volume_num-barh.mode),(long)(sizeof(barh)));
  255. printf("offsets = %ld %ld %ld %ld\n",(long)((char*)&macbinh.finfo-&macbinh.nlen),
  256. (long)(macbinh.unused-&macbinh.nlen),(long)((char*)&macbinh.lastbyte17/*headlen[0]*/-&macbinh.nlen),
  257. (long)(sizeof(macbinh)));
  258. }
  259. #endif
  260.  
  261.  
  262. for(;;){
  263.     fase=non_faccio_nulla;
  264.     set_skip_all(0);
  265.     if(last_file_opened==files_to_be_opened) close_all_open_WD();
  266.     check_ev_timing=120;
  267.     flush_buffers();
  268.     enable_autoflush();
  269.  
  270.     last_selection=0;
  271.     while(last_selection==0){
  272.         if(last_file_opened!=files_to_be_opened && !file_aperto && !drive_number)
  273.             last_selection=menuItemMess(fileID,fmOpen);
  274.         else
  275.             MainEvent();
  276.         }
  277.     fase=ricevuto_comando;
  278.     settori_passati=0;
  279.  
  280. /* sono possibili solo i menù Special e File, perché Preferences ed Edit sono gestiti 
  281. subito e Write non è abilitato */
  282.     if(hiword(last_selection)==hackID){
  283.         if(loword(last_selection)==hmDriveList)
  284.             DriveList();    /* it's the only command which needs no disk...*/
  285.         else
  286.             hacking(loword(last_selection));
  287.         }
  288. /* non faccio else perché si può uscire dall'hacking anche con un comando
  289. del menù File, che va eseguito 
  290. -- don't do 'else': I can exit from hacking with a File menu command which must be
  291. executed */
  292.  
  293.     command=loword(last_selection);
  294.  
  295.     if(hiword(last_selection)==fileID){
  296.         again_command=0;
  297.         last_selection=0;
  298.         if(command==fmGetInfo){
  299.             listonly=2;
  300.             apri_archivio(aa_getinfo,0);
  301.             }
  302.         else if(command==fmOpen){
  303.             listonly=0;
  304.             if(last_file_opened!=files_to_be_opened){
  305.                 apri_archivio(aa_load,++last_file_opened);
  306.                 }
  307.             else
  308.                 apri_archivio(aa_open,0);
  309.             }
  310.         else if(command==fmClose){
  311.             if(file_aperto)
  312.                 chiudi_archivio();
  313.             else
  314.                 diskEject();
  315.             }
  316.         else if(command ==fmCopy)
  317.             copia_da_disco_a_file();
  318.         else if(command==fmList){
  319.             listonly=1;
  320.             estrai_da_floppy();
  321.             }
  322.         else if(command==fmExtract){ /* extract, con de-macBinarizzazione e conversione LF->CR */
  323.             listonly=0;
  324.             estrai_da_floppy();
  325.             }
  326.         else if(command==fmSelect)
  327.             select_and_extract();
  328.         else if(command==fmWriteTar||command==fmWriteBar||command==fmAppend){
  329.             bar_archive= command==fmWriteBar;    /* non valido nel caso di append */
  330.             append_mode= command==fmAppend;
  331.             scrivi_su_floppy();
  332.             }
  333.         else if(command==fmFormat){
  334.             disk_initialize();
  335.             }
  336.         }
  337.     }
  338. }
  339.  
  340. /**************** apri/chiudi archivio su file ***********/
  341.  
  342. void apri_archivio(mode,indice)        /* open a file archive */
  343. enum aa_mode mode;
  344. short indice;
  345. {
  346. long filesize;
  347. short nLF,forza_formato;
  348. FileParam fpb;
  349. Boolean not_ask_type,do_not_open;
  350. extern long file_date;
  351.  
  352. if(setjmp(main_loop)<0) {
  353.     return;
  354.     }
  355.  
  356. if(mode==aa_getinfo){
  357.     SFTypeList    myTypes;
  358.     my_SF_Get(-1,myTypes);
  359.     if(!reply.good) return;
  360.     not_ask_type=true;
  361.     }
  362. else if(mode==aa_open){
  363.     if(! get_file_with_checkbox(¬_ask_type)) return;
  364.     }
  365. else{    /* aa_load */
  366.     AppFile fileInfo;
  367.     GetAppFiles (indice,&fileInfo);
  368.     ClrAppFiles (indice);
  369.     reply.vRefNum=fileInfo.vRefNum;
  370.     pStrcpy(reply.fName,fileInfo.fName);
  371.     not_ask_type=true;
  372.     printf("File %P\n",reply.fName);
  373.     }
  374.  
  375. fpb.ioFVersNum = 0;
  376. fpb.ioFDirIndex = 0;
  377. fpb.ioVRefNum=reply.vRefNum;
  378. fpb.ioNamePtr=reply.fName;
  379. if (PBGetFInfoSync(&fpb)) pbsyserr(&fpb);
  380. filesize=fpb.ioFlLgLen;
  381. sectors_on_floppy= (filesize+511)>>9;
  382.  
  383. if(listonly){
  384.     disable_autoflush(2);
  385.     one_empty_line();
  386.     printf("File %P ",reply.fName);
  387.     printf("(data %ld+res %ld bytes)",fpb.ioFlLgLen,fpb.ioFlRLgLen);
  388. #if 0
  389. #define ALIAS_BIT 0x8000
  390.     if(fpb.ioFlFndrInfo.fdFlags & ALIAS_BIT) printf(" alias");    /* currently
  391.     that's useless, I'm using a non-custom standard file, which resolves aliases ! */
  392. #endif
  393.     printf("\n");
  394.     print_one_date(fpb.ioFlCrDat,in_Italia?"creato     ":"created  ");
  395.     printf("\n");
  396.     print_one_date(fpb.ioFlMdDat,in_Italia?"modificato ":"modified ");
  397.     printf("\n");
  398.     print_type_creator(fpb.ioFlFndrInfo.fdType,fpb.ioFlFndrInfo.fdCreator);
  399.     printf("\n");
  400.     enable_autoflush();
  401.     }
  402. else
  403.     one_empty_line();
  404.  
  405. pStrcpy(tarh.name,reply.fName);
  406. my_p2cstr(tarh.name);    /* these statements are useful only if the file is not */
  407. bar_archive=0;        /* a tar/bar archive */
  408.  
  409. /* tarh.mtime is examined later, nothing bad happens if it contains garbage
  410. but that's not good programming style */
  411. strcpy(tarh.mtime,"0");
  412. sect_n=0;
  413. end_of_file();    /* forse non necessario, ma prudente */
  414. copia_ultimo_header(&tarh,(sector_t)0);    /* gli devo passare il numero del
  415.                         settore successivo all'header */
  416.  
  417. if(filesize!=0 && !not_ask_type)
  418.     forza_formato=dialogo_tipo_file();
  419. else
  420.     forza_formato=0;
  421.  
  422. do_not_open=true;
  423. if(!forza_formato && fpb.ioFlFndrInfo.fdType=='APPL')
  424.     printf(in_Italia?"Applicazione\n":"Application\n");
  425. else if(!forza_formato && fpb.ioFlFndrInfo.fdType=='INIT')
  426.     printf(in_Italia?"Estensione\n":"Extension\n");
  427. else if(!forza_formato && fpb.ioFlFndrInfo.fdType=='cdev')
  428.     printf(in_Italia?"Pannello di controllo\n":"Control panel\n");
  429. else if(!forza_formato && (fpb.ioFlFndrInfo.fdType=='DFIL'||fpb.ioFlFndrInfo.fdType=='dfil'))
  430.     printf(in_Italia?"Accessorio di scrivania\n":"Desk Accessory\n");
  431. else if(filesize==0)
  432.     printf(in_Italia?"Data fork vuota\n":"Empty data fork\n");
  433. else
  434.     do_not_open=false;
  435. if(do_not_open){
  436.     if(!listonly) printf(in_Italia?"Questo tipo di file non può essere aperto da suntar\n":
  437.         "This file type can\'t be opened by suntar\n");
  438.     return;
  439.     }
  440.  
  441. /* Open the file only now, and don't open files with empty data fork:
  442. Disk Doubler extracts the resource fork of compressed files if I do that,
  443. but that's time consuming and useless */
  444.  
  445. if(apri_file("rb",&inputFile))
  446.     return;
  447.  
  448. file_aperto=ff_tarbar;
  449. file_current_s=-1;
  450.  
  451. if(forza_formato==ff_packit || forza_formato==0 && fpb.ioFlFndrInfo.fdType=='PIT '){
  452.     /* don't examine the creator, there is at least one program (unpit)
  453.     which creates PackIt files with another creator ('UPIT') */
  454.     if(listonly)
  455.         printf(in_Italia?"Archivio PackIt\n":"PackIt archive\n");
  456.     else{
  457.         select_directory();
  458.         if(reply.good){
  459.             file_date= -1;
  460.             one_empty_line();
  461.             printf(in_Italia?"Estrazione da archivio PackIt %s\n":
  462.                 "Unpacking PackIt archive %s\n", tarh.name);
  463.             my_unpit();
  464.             printf(in_Italia?FINITO:DONE);
  465.             fine_lavoro();
  466.             }
  467.         chiudi_archivio();
  468.         }
  469.     }
  470. else if(!forza_formato&&is_hqx_name()>0 || forza_formato==ff_binhex){
  471.     macbinh.cdate=fpb.ioFlCrDat;
  472.     macbinh.mdate=fpb.ioFlMdDat;
  473. /*    dopo di che non deve essere chiamato chkmacbin, che scarabocchia su macbinh...*/
  474.  
  475.     file_aperto=ff_binhex;
  476.     fase=reading_disk;
  477.  
  478.     if(listonly)
  479.         untar_file(filesize);
  480.     else{
  481.         select_directory();
  482.         if(reply.good){
  483.             one_empty_line();
  484.             untar_file(filesize);
  485.             printf(in_Italia?FINITO:DONE);
  486.             fine_lavoro();
  487.             }
  488.         chiudi_archivio();
  489.         }
  490.     }
  491. else if((forza_formato==0 || forza_formato==ff_macbin||forza_formato==ff_c_macbin) &&
  492.         chkmacbin (filesize,forza_formato)){
  493.     file_aperto=ff_macbin;
  494.     fase=reading_disk;
  495.  
  496.     copia_ultimo_header(&tarh,(sector_t)0);
  497.     if(listonly)
  498.         untar_file(filesize);
  499.     else{
  500.         select_directory();    /* per la verità, salvando un solo file potrei usare uno
  501.                         standard put, ma significherebbe fare modifiche più
  502.                         pesanti di quanto non voglia
  503.                         --having only one file to save I could use SFPutFile, but
  504.                         the existing routines don't expect more than a destination 
  505.                         folder, and suntar was NOT meant as a file format converter,
  506.                         even if it can convert file formats, hence these commands
  507.                         are implemented according to the principle of "do that in
  508.                         the fewest statements with the fewest changes to existing
  509.                         routines"
  510.                         */
  511.         if(reply.good){
  512.             one_empty_line();
  513.             untar_file(filesize);
  514.             printf(in_Italia?FINITO:DONE);
  515.             fine_lavoro();
  516.             }
  517.         chiudi_archivio();
  518.         }
  519.     }
  520. else if(forza_formato==ff_macbin||forza_formato==ff_c_macbin)
  521.     error_message(in_Italia?"Formato non MacBinary\n":"Not a Macbinary file\n");
  522. else if(forza_formato==ff_ASCII||!forza_formato && isASCII(filesize,&nLF)>0  ){
  523.     file_aperto=ff_ASCII;
  524.     fase=reading_disk;
  525.  
  526.     if(listonly){
  527.         printf(in_Italia ?"Contenente testo ASCII":"Containing ASCII text");
  528.         if(nLF>0) printf(in_Italia?" con LF":" using LF");
  529.         printf("\n");
  530.         }
  531.     else if(nLF==0){
  532.         printf(in_Italia?"Testo ASCII in formato Macintosh, nessuna conversione\n":
  533.             "ASCII text in Macintosh format, no conversion\n");
  534.         chiudi_archivio();
  535.         }
  536.     else{
  537.         if(reply.fName[0]>63-4) reply.fName[0]=63-4;
  538.         pStrcat(reply.fName,"\p.out");
  539.         my_SF_Put(in_Italia?"\pSalva testo Mac col nome:":"\pSave Mac text as:",reply.fName);
  540.         if(reply.good){
  541.             register short i;
  542.             if(new_text_file(&info_file)==0){
  543.                 printf(in_Italia?"Converto %s in %P\n":"Converting %s to %P\n",tarh.name,reply.fName);
  544.                 info_file_open=1;
  545.                 while(filesize>0){
  546.                     if(filesize>=512L) i=512; else i= (short)filesize;
  547.                     filesize -= i;
  548.                     if(readblock(disk_buffer,i)!=0){
  549.                         disk_error_message();
  550.                         raise_error();
  551.                         }
  552.  
  553.                     macize_ASCII(disk_buffer,512);
  554.                     if(mac_fwrite(disk_buffer,i,info_file)<0)
  555.                         write_error_message();
  556.                     }
  557.                 FSClose(info_file);
  558.                 info_file_open=0;
  559.                 }
  560.             else
  561.                 error_message(in_Italia?"Errore nell\'apertura del file\n":"Error opening file\n");
  562.             printf(in_Italia?FINITO:DONE);
  563.             fine_lavoro();
  564.             }
  565.         chiudi_archivio();
  566.         }
  567.     }
  568. else{    /* the file is opened as a tar/bar archive */
  569.     if(!listonly){
  570.         one_empty_line();
  571.         printf(in_Italia?"Apertura file %s\n":
  572.             "Opening file %s\n", tarh.name);
  573.         (void)identify_format();
  574.         /*printf("\n");*/
  575.         }
  576.     else
  577.         (void)identify_format();
  578.     }
  579. if(listonly){
  580.     chiudi_archivio();
  581.     /*printf("\n");*/
  582.     }
  583. }
  584.  
  585. void chiudi_archivio()
  586. {
  587. file_aperto=0;
  588. FSClose(inputFile);
  589. }
  590.  
  591. /***************** copia da disco a file ******************/
  592.  
  593. void copia_da_disco_a_file()            /* copy a disk archive to a file archive */
  594. /* trasferisce quello che vede in un file tar, senza estrarre i singoli files */
  595. {
  596. sector_t more_sectors;
  597. short inPlace;
  598. Boolean fine;
  599. long length;
  600. short outputFile;
  601. static unsigned char nome_ita[]="\parchivio",  eng_name[]="\parchive";
  602.  
  603. listonly=0;    /* ad uso di floppy swap, le altre routines non le chiamo */
  604.  
  605. if(setjmp(main_loop)<0) {
  606.     FSClose(outputFile);    /* non lo metto in raise_error... */
  607.     return;
  608.     }
  609.  
  610. if(aspetta_inserzione(in_Italia?"\pInserisci il disco in formato UNIX":
  611.     "\pInsert the disk in UNIX format",false) || di.is_not_initialized){
  612.         FSClose(outputFile);
  613.         return;
  614.         }
  615.  
  616.  
  617. more_sectors=0;
  618.  
  619. fase=reading_disk;
  620. bar_archive= identify_format()==bar_format;
  621.  
  622. if(bar_archive){
  623.     if( my_atoi(((barh_type*)disk_buffer)->volume_num,&floppy_n)) floppy_n = -1;
  624.     if(floppy_n!=1) error_message(in_Italia?"Questo non è il primo disco\n":
  625.         "That\'s not the first disk\n");
  626.     }
  627.  
  628. pStrcpy(disk_buffer,in_Italia?nome_ita:eng_name);
  629. pStrcat(disk_buffer,bar_archive?"\p.bar":"\p.tar");
  630.  
  631. my_SF_Put(in_Italia?"\pSalva col nome:":"\pSave as:",disk_buffer);
  632. if(!reply.good) return;
  633.  
  634. if(apri_file("wb",&outputFile)) return;
  635.  
  636. one_empty_line();
  637. printf(in_Italia?"Inizio lettura\n":START_READ);
  638.  
  639. if(!bar_archive)
  640.     tar_check_floppy_swap(1);    /* ci sono delle inizializzazioni */
  641. else{
  642.     leggi_settore(0,&disk_buffer);
  643.     if(check_error()) raise_error();
  644.     if(mac_fwrite(disk_buffer, 512, outputFile)<=0){
  645.         beep_in_foreground();
  646.         write_error_message();
  647.         }
  648.     bar_check_floppy_swap(1);
  649.     }
  650.  
  651. leggi_settore(sect_n,&disk_buffer);
  652. if(check_error()) raise_error();
  653.  
  654. do{
  655.     if(mac_fwrite(disk_buffer, 512, outputFile)<=0){
  656.         beep_in_foreground();
  657.         write_error_message();
  658.         }
  659.     check_events();
  660.     fine = more_sectors==0;        /* fine del file corrente 
  661.                                 -- end of current file ? */
  662.     if(fine){
  663.         fine= check_all_zero(disk_buffer);    /* fine dell'intero archivio
  664.                                         -- end of the archive ? */
  665.         if(!fine){
  666.             unsigned char linkflag = get_linkflag(&length,true);
  667.             last_offset=0;
  668.             copia_ultimo_header(disk_buffer,sect_n+1);    /* gli devo passare il numero del
  669.                         settore successivo all'header, da qui il +1 */
  670.             if(length<0)
  671.                 fine=true;
  672.             else{
  673.                 print_info(bar_archive?((barh_type*)disk_buffer)->name:disk_buffer,length);
  674.                 more_sectors=(length+511)/512;
  675.                 }
  676.             }
  677.         }
  678.     else
  679.         more_sectors--;
  680.  
  681.     if(!fine){
  682.         sect_n++;
  683.         if(bar_archive)
  684.             bar_check_floppy_swap(more_sectors==0?-1:0);
  685.         else
  686.             tar_check_floppy_swap(more_sectors==0?-1:0);
  687.         leggi_settore(sect_n,&disk_buffer);
  688.         if(check_error()) raise_error();
  689.         }
  690.     }
  691. while(!fine);
  692.  
  693. one_empty_line();
  694. printf(in_Italia ? "Lettura completata\n" : "Read completed\n");
  695. diskEject();
  696. FSClose(outputFile);
  697. fine_lavoro();
  698. }
  699.  
  700. /***************** estrai da floppy ******************/
  701.  
  702. void estrai_da_floppy()        /* extract or list */
  703. {
  704. enum formats fmt;
  705.  
  706. if(setjmp(main_loop)<0) {
  707.     return;
  708.     }
  709.  
  710. if(!listonly){
  711.     select_directory();
  712.     if(!reply.good) return;
  713.     }
  714.  
  715. if(aspetta_inserzione(in_Italia?"\pInserisci il disco in formato UNIX":
  716.     "\pInsert the disk in UNIX format",false) || di.is_not_initialized) return;
  717. one_empty_line();
  718. printf(in_Italia?"Inizio lettura\n":START_READ);
  719.  
  720. disco_espulso=!listonly;    /* per un extract non mi interessa impedire di espellere... */
  721. fase=reading_disk;
  722.  
  723. fmt=identify_format();
  724. if(fmt==tar_format)
  725.     my_untar();
  726. else if(fmt==bar_format)
  727.     my_unbar();
  728.  
  729. if(disco_espulso) diskEject();
  730. fine_lavoro();
  731. }
  732.  
  733.  
  734. /************ scrivi su floppy ******************/
  735.  
  736.  
  737. Boolean ins_checkbox_status;
  738.  
  739. void set_exam_checkbox(WindowRecord *);
  740. static void set_exam_checkbox(w)
  741. WindowRecord *w;
  742. {
  743. short    kind;
  744. Handle    h;
  745. Rect    r;
  746. extern Boolean sm_checkbox_status;
  747.  
  748. sm_checkbox_status=ins_checkbox_status;
  749. GetDItem(w,4,&kind,&h,&r);
  750. SetCtlValue((ControlHandle)h,sm_checkbox_status);
  751. }
  752.  
  753. void scrivi_su_floppy()        /* handling of the Write menu */
  754. {
  755. Boolean ok_to_proceed;
  756. extern Boolean sm_checkbox_status;
  757.  
  758. if(setjmp(main_loop)<0) {
  759.     return;
  760.     }
  761.  
  762. ok_to_proceed=false;
  763.  
  764. ins_checkbox_status=false;
  765.  
  766. do{
  767.     sm_checkbox_status=false;    /* if the disk was in, nobody else clears it */
  768.     if(aspetta_inserzione(in_Italia?"\pInserisci il disco su cui scrivere":
  769.         "\pInsert the disk to be written",!append_mode)) return;
  770.     ins_checkbox_status=sm_checkbox_status;
  771.  
  772.     if(is_wrprot() && (di.is_not_initialized||!ins_checkbox_status) ){
  773.         printf_protetto();
  774.         SysBeep(5);
  775.         return;
  776.         }
  777.  
  778.     if(di.is_not_initialized){
  779.         disk_format(false);
  780.         if(drive_number==0 && append_mode) return;
  781.         }
  782.     else{
  783.         if(ins_checkbox_status){
  784.             esamina_disco();
  785.             if(drive_number==0)
  786.                 ;
  787.             else if(is_wrprot()){
  788.                 printf_protetto();
  789.                 return;
  790.                 }
  791.             else
  792.                 ok_to_proceed= warning_400_800()!=1;
  793.             }
  794.         else
  795.             ok_to_proceed= warning_400_800()!=1;
  796.         }
  797.     }
  798. while(!ok_to_proceed);
  799.  
  800.  
  801. leggi_settore(0,&disk_buffer);    /* serve come controllo di errore, e poi non so,
  802.                             potrebbe essere utile per la faccenda del TagBuffer */
  803. if(check_error()) return;
  804.  
  805. fase=reading_disk;
  806.  
  807. reset_sector_count();
  808. one_empty_line();
  809. if(append_mode){
  810.     cerca_fine();
  811.     }
  812. else
  813.     printf(in_Italia?"Nuovo archivio %car\n":"New %car archive\n",bar_archive?'b':'t');
  814.  
  815. for(;;){
  816.     unsigned char itemname[32];
  817.     fase=in_writing;
  818.     print_ready();
  819.     settori_passati=0;
  820.     EnableItem(writeMenu, 0);
  821.     GetIndString (itemname,128,bar_archive?2:1);
  822.     SetItem (writeMenu,wmWriteTar,itemname);
  823.     EnableDisableItem(writeMenu,wmSetLabel,bar_archive);
  824.  
  825.     DrawMenuBar();
  826.     close_all_open_WD();
  827.     check_ev_timing=120;
  828.     flush_buffers();
  829.     enable_autoflush();
  830.     last_selection=0;
  831.     while(last_selection==0){
  832.         if(!bar_archive) EnableDisableItem(writeMenu,wmSetLabel,tar_version==tar_GNU);
  833.         MainEvent();
  834.         }
  835.     DisableItem(writeMenu, 0);
  836.     DrawMenuBar();
  837.  
  838.     if(last_selection==menuItemMess(fileID,fmAbort) ||
  839.        last_selection==menuItemMess(writeID,wmEndWrite) ||
  840.        last_selection==menuItemMess(fileID,fmEject) ){
  841.         if(last_selection!=menuItemMess(writeID,wmEndWrite)) diskEject();
  842.         return;
  843.         }
  844.     else if(hiword(last_selection)==writeID){
  845.         my_tar(loword(last_selection));
  846.         fine_lavoro();
  847.         }
  848.     /* non ci sono altri menù attivi: in principio pensavo di lasciare il List 
  849.     (senza espellere!) ma non serve, man mano che scrivo files sulla console
  850.     vengono scritti i nomi ! */
  851.     }
  852. }
  853.  
  854.  
  855. void disk_initialize()
  856. {
  857. short inPlace;
  858. short i;
  859.  
  860. fase=initializing;
  861.  
  862. i=aspetta_inserzione(in_Italia ? "\pInserisci il disco da inizializzare":
  863.     "\pInsert the disk to be initialized",false);
  864.  
  865. i=testa_stato(&inPlace,0);
  866. if(i!=0 || !inPlace){
  867.     diskEject();
  868.     return;
  869.     }
  870. if(is_wrprot()){
  871.     printf_protetto();
  872.     SysBeep(5);
  873.     return;
  874.     }
  875. if(warning_first_write(1)<0){
  876.     diskEject();
  877.     return;
  878.     }
  879.  
  880. disk_format(crea_mac_dir);
  881. if(drive_number){
  882.     if(testa_stato(&inPlace,1)){
  883.         diskEject();
  884.         }
  885.     }
  886. }
  887.  
  888.  
  889. /*************************************************/
  890.  
  891. enum formats identify_format()
  892. /* asks to the device driver about the current disk, than examines the
  893. first sectors to see whether it's a tar or bar archive */
  894. {
  895. short i;
  896. sector_t j;
  897. #define SUPERDRIVE    4
  898.  
  899. leggi_settore(0,disk_buffer);
  900. if(err_code<0){
  901.     SysBeep(5);
  902.     if(file_aperto){
  903.         if(err_code==eofErr)
  904.             printf(in_Italia?"Data fork vuota\n":"Empty data fork\n");
  905.         else
  906.             printf("File access error %d\n",err_code);
  907.         }
  908.     else if( drive_number<=4 && (i=drive_type[drive_number-1]&0x0F)!= SUPERDRIVE &&
  909.         i!= SUPERDRIVE+1){
  910.         printf(in_Italia ? "Disco non inizializzato o in formato 720/1440K\n" : 
  911.             "The disk is either uninitialized or 720/1440K\n");
  912.         printf(in_Italia ? "Prova a inserirlo in un Superdrive" :
  913.             "Try to insert it in a SuperDrive");
  914.         if(n_superdrives==0)
  915.             printf(in_Italia?" (su un Macintosh che ce l\'abbia)":
  916.             " (on a Macintosh which has one)");
  917.         printf("\n");
  918.         }
  919.     else if(di.is_not_initialized)
  920.         printf(in_Italia ? "Disco non inizializzato\n" :
  921.             "The disk is not initialized\n");
  922.     else
  923.         printf(in_Italia ? "Disco illeggibile\n" :
  924.             "The disk is unreadable\n");
  925.  
  926.     return unreadable_disk;
  927.     }
  928. previousFormat=tar_unknown;
  929.  
  930. if( (fase==non_faccio_nulla || fase==in_writing) && di.os!=unknown_os)
  931.     return unknown_format;    /* durante un list o altro devo dire che il
  932.             formato non è tar, ma per una unexpected_disk_insertion non
  933.             c'è motivo di dare altri messaggi */
  934.  
  935. if(di.os==mac_MFS||di.os==mac_HFS){
  936.     /* disk_buffer still contains sector 0 */
  937.     if(check_all_zero(disk_buffer) ){
  938.         printf(in_Italia ? "Il disco non è in formato tar né bar\n" : 
  939.             "The disk format is neither tar nor bar\n");
  940.         return unknown_format;    /* A Mac disk
  941.         with a null sector 0 should not be classified as an empty tar archive */
  942.         }
  943.     }
  944.     
  945.  
  946. i = tar_check_settore0(false);
  947. if(i>=0){
  948.     if(previousFormat==tar_GNU)
  949.         printf(in_Italia ? "Archivio in formato GNU tar\n" : "GNU tar archive\n");
  950.     else
  951.         printf(in_Italia ? "Archivio in formato tar\n" : "Tar archive\n");
  952.     return tar_format;
  953.     }
  954. i= bar_check_settore0(&j,false);
  955. if(i>=0){
  956.     printf(in_Italia ? "Archivio in formato bar\n" : "Bar archive\n");
  957.     return bar_format;
  958.     }
  959. else{
  960. /* I controlli fatti da quelle routines sono rigorosi, basta che il checksum 
  961. sia sbagliato...  non vorrei solo per quello perdere ogni
  962. possibilità di esaminare il disco, la vecchia versione non è affatto rigida in
  963. proposito e neanche la nuova lo è per gli altri header, quindi faccio una 
  964. discriminazione molto più approssimativa, tanto my_untar e my_unbar poi hanno
  965. dei controlli di errore */
  966.  
  967.     if(((barh_type*)disk_buffer)->bar_magic[0]== 'V' && 
  968.         untar_dec_number(((barh_type*)disk_buffer)->volume_num,-1)!=-1){
  969.         printf(in_Italia ? "Archivio in probabile formato bar\n" : "It looks like a bar archive\n");
  970.            return bar_format;
  971.            }
  972.     else if(untar_number(((tarh_type*)disk_buffer)->size,-1)!=-1 && 
  973.         untar_number(((tarh_type*)disk_buffer)->mtime,-1)!=-1){
  974.         printf(in_Italia ? "Archivio in probabile formato tar\n" : "It looks like a tar archive\n");
  975.          return tar_format;
  976.          }
  977.     else{
  978.         if(fase!=hack_listing){
  979.             SysBeep(5);
  980.             disable_autoflush(2);
  981.             if(file_aperto)
  982.                 printf(in_Italia ? "Il file" : "The file");
  983.             else
  984.                 printf(in_Italia ? "Il disco" : "The disk");
  985.             printf(in_Italia ? " non è in formato tar né bar" : 
  986.                 " format is neither tar nor bar");
  987.             if(!file_aperto&&tar_version==tar_AIX)
  988.                 printf(in_Italia?" (ma potrebbe essere un disco tar oltre il primo)":
  989.                     " (but it could be a tar disk following the first one)");
  990.             printf("\n");
  991.             enable_autoflush();
  992.             }
  993.         return unknown_format;
  994.         }
  995.     }
  996. }
  997.  
  998.  
  999. /***************** apri file *********************/
  1000.  
  1001. short apri_file(modo,who)        /* opens a file */
  1002. char *modo;
  1003. short *who;
  1004. {
  1005. short io;
  1006.  
  1007. reply.fName[reply.fName[0]+1]='\0';    /* per il caso debba fare una printf...*/
  1008. /* SetVol(NULL,reply.vRefNum);  setta la directory: inutile */
  1009.  
  1010. if(modo[0]=='r')
  1011.     io=FSOpen (reply.fName, reply.vRefNum, who);
  1012. else if(modo[0]=='w')
  1013.     if(bar_archive)
  1014.         io=create_overwrite(bar_creator, bar_type, who);
  1015.     else
  1016.         io=create_overwrite(tar_creator, 'TARF', who);
  1017. if(io!=noErr) {
  1018.     start_of_line();
  1019.     printf("failure opening %P (",reply.fName);
  1020.     if(io==opWrErr)
  1021.         printf("already open with write permission)\n");
  1022.     else
  1023.         printf("error %d)\n",io);
  1024.     return -1;
  1025.     }
  1026. return 0;
  1027. }
  1028.  
  1029. OSErr new_text_file(outputFile)        /* creates and opens a text file */
  1030. short *outputFile;
  1031. {
  1032. short io;
  1033. /* SetVol(NULL,reply.vRefNum); setta la directory: inutile e pericoloso */
  1034.  
  1035. return create_overwrite(text_creator, 'TEXT',outputFile);
  1036. }
  1037.  
  1038. OSErr create_overwrite(c,t,who)
  1039. OSType t,c;
  1040. short *who;
  1041. {
  1042. OSErr io;
  1043. io=Create(reply.fName, reply.vRefNum, c, t);
  1044. if (io==noErr)
  1045.     io = FSOpen( reply.fName, reply.vRefNum, who );
  1046. else if(io==dupFNErr){
  1047.     io = open_overwrite( reply.fName, reply.vRefNum, who );
  1048.     if(io==noErr){
  1049. /* settare tipo e creatore: certo se il file esiste già dovrebbero
  1050. essere gli stessi, ma meglio non fidarsi !
  1051. -- type and creator must be modified
  1052. */
  1053.         FileParam fpb;
  1054.         fpb.ioFVersNum = 0;
  1055.         fpb.ioFDirIndex = 0;
  1056.         fpb.ioVRefNum=reply.vRefNum;
  1057.         fpb.ioNamePtr= &reply.fName;
  1058.         if (PBGetFInfoSync(&fpb)==noErr){
  1059.             fpb.ioFlFndrInfo.fdType=t;
  1060.             fpb.ioFlFndrInfo.fdCreator=c;
  1061.             PBSetFInfoSync(&fpb);
  1062.             }
  1063.         }
  1064.     }
  1065. return io;
  1066. }
  1067.  
  1068. short mac_fread(buff,nbytes,refNum)
  1069. char *buff;
  1070. short nbytes;
  1071. short refNum;
  1072. {
  1073. long count = nbytes;
  1074. if( (err_code=FSRead( refNum, &count, buff )) != noErr){
  1075.     if(err_code==eofErr){
  1076.         fillmem(&buff[count],0,512-(short)count);
  1077.         err_code=noErr;
  1078.         }
  1079.     else
  1080.         return -1;
  1081.     }
  1082. return (short) count;
  1083. }
  1084.  
  1085. short mac_fwrite(buff,nbytes,refNum)
  1086. char *buff;
  1087. short nbytes;
  1088. short refNum;
  1089. {
  1090. long count=nbytes;
  1091. if( (err_code=FSWrite( refNum, &count, buff )) != noErr )
  1092.     return -1;
  1093. return (short)count;
  1094. }
  1095.  
  1096. OSErr open_overwrite (fileName,vRefNum,refnum)
  1097. /* apre la data fork del file, tagliando a zero bytes sia questa sia la
  1098. resource fork
  1099. -- opens the file data fork, truncating it and the resource fork to zero length
  1100. */
  1101. char *fileName;
  1102. short vRefNum,*refnum;
  1103. {
  1104. short i = FSOpen(fileName,vRefNum, refnum);
  1105. if(i==noErr){
  1106.     SetEOF(*refnum,0L);
  1107.     if( OpenRF (fileName,vRefNum,&i)==noErr){
  1108.         SetEOF(i,0L);
  1109.         FSClose(i);
  1110.         }
  1111.     i=noErr;
  1112.     }
  1113. return i;
  1114. }
  1115.  
  1116. /**************** gestione eventi durante le operazioni ************/
  1117.  
  1118. Boolean my_disk_is_in()
  1119. {
  1120. /* Called before exiting from a pause: checks whether the disk is where is
  1121. expected, and if there are some obvious reasons to believe it's not the
  1122. expected disk
  1123. */
  1124. static char s1[]="Disco cambiato !\n",
  1125.     s2[]="Changed disk !\n";
  1126.     {
  1127.     short inPlace;
  1128.     sector_t old_s=sectors_on_floppy;
  1129.     if (testa_stato(&inPlace,0) || !inPlace){
  1130.         printf(in_Italia?"Disco assente !\n" : "Missing disk !\n");
  1131.         flush_console();
  1132.         return false;
  1133.         }
  1134.     if(sectors_on_floppy!=old_s){
  1135.         sectors_on_floppy=old_s;
  1136.         printf(in_Italia?s1:s2);
  1137.         return false;
  1138.         }
  1139.     sectors_on_floppy=old_s;
  1140.     }
  1141.     {
  1142.     char buffer[512];
  1143.     short refnum;
  1144.     long space;
  1145.     enum os_type i;
  1146.     if( GetVInfo (drive_number, buffer, &refnum,&space) == nsvErr ) return true;
  1147.          /* no such volume: a non-Mac disk is not mounted hence...*/
  1148.     read_one_sector(2,buffer,drive_number);
  1149.     if(!err_code) i=riconosci_disco_mac(buffer);
  1150.     if(err_code || i!=mac_HFS&&i!=mac_MFS){
  1151.         UnmountVol (NULL,drive_number);    /* however, 
  1152.              in some cases (see comments to de_Mac_ize) it's mounted, at least if
  1153.              suntar is not in foreground */;
  1154.         return true;
  1155.         }
  1156.     printf(in_Italia?s1:s2);
  1157.     return false;
  1158.     }
  1159. }
  1160.  
  1161. void handle_pause()
  1162. {
  1163.     enum tipo_fase old=fase;
  1164.     extern DialogPtr ListDialog;
  1165.     fase=paused;
  1166.     last_selection=0;
  1167.  
  1168.     if(my_windows[0].used) SetWTitle (&my_windows[0],in_Italia?"\p<< in pausa >>":"\p<< paused >>");
  1169.     {unsigned char itemname[32];
  1170.     GetIndString(itemname,129,4);
  1171.     SetItem (myMenus[fileM], fmPause, itemname);
  1172.     }
  1173.     flush_all();
  1174.  
  1175.     while(last_selection!=menuItemMess(fileID,fmPause) && 
  1176.           last_selection!=menuItemMess(fileID,fmAbort)){
  1177.         MainEvent();    /* be', non tutti
  1178.             i filtri ha senso chiamarli anche durante un pause, ma in realtà
  1179.             il pause non è attivo durante i filtri che "lavorano" come
  1180.             quello del disk insertion, restano solo quelli dei dialoghi che
  1181.             vanno chiamati perché gestiscono gli update
  1182.             --not all filters must continue to be called during a pause,
  1183.             but when pause is enabled some filters are not used, and the
  1184.             filters of semimodal and of the selection dialog must be called
  1185.             during pauses
  1186.             */
  1187.         if(last_selection==menuItemMess(fileID,fmPause) && drive_number && !my_disk_is_in() ){
  1188.             last_selection=0;
  1189.             }
  1190.         }
  1191.     if(last_selection==menuItemMess(fileID,fmPause)) last_selection=0;
  1192.     {unsigned char itemname[32];
  1193.     GetIndString(itemname,129,3);
  1194.     SetItem (myMenus[fileM], fmPause, itemname);
  1195.     }
  1196.     if(my_windows[0].used) SetWTitle (&my_windows[0],window_title);
  1197.     fase=old;
  1198. }
  1199.  
  1200. Boolean check_filter(EventRecord *);    /* Think C 5 no more requires these
  1201.     silly prototypes before a function declaration, but only for static functions,
  1202.     and anyway suntar must still be compilable by Think C 4 */
  1203. static Boolean check_filter(theEvent)
  1204. /* event filter used while suntar is working: most events are ignored
  1205. without being handled
  1206. */
  1207. EventRecord *theEvent;
  1208. {
  1209. switch(theEvent->what){
  1210. case keyDown:
  1211.     if(theEvent->modifiers&cmdKey) break;    /* se accetta la selezione menù deve
  1212.                                             accettare anche i command-tasto */
  1213.     /* else prosegui in sequenza 
  1214.     -- else, since there is no break, continue with the following instruction */
  1215. case autoKey:
  1216.     return false;    /* the event must not be handled */
  1217.     break;
  1218. case mouseDown:
  1219.     {
  1220.     WindowPtr        whichWindow;
  1221.     short code=FindWindow( theEvent->where, &whichWindow );
  1222.     if(code!=inMenuBar && code!=inSysWindow && code!=inDrag &&
  1223.         code!=inGrow && whichWindow==FrontWindow())
  1224.         return false;
  1225.     else
  1226.         SetCursor(&arrow);
  1227.     }
  1228.     break;
  1229. }
  1230. return true;
  1231. }
  1232.  
  1233.  
  1234. void check_events()
  1235. /* handle the events which are allowed while suntar is working, including
  1236. the Pause command
  1237. */
  1238. {
  1239. EventRecord        myEvent;
  1240.  
  1241. /* We've discovered that, in typical file extractions, check_events occupied up
  1242. to 35% of processing time, even if no event was pending. Hence, events must be
  1243. checked less often, but with care, otherwise suntar would lose its feel (it's
  1244. good to be able to change preferences on the fly, and while it's working in
  1245. background one does not like to notice a huge speed difference in the foreground
  1246. application) */
  1247.  
  1248. if(last_selection!=menuItemMess(fileID,fmPause)){ /* that's used by the following function */
  1249.     ++check_ev_timing;
  1250.     if( check_ev_timing< (gInBackground?back_prio:(fase!=reading_disk&&fase!=hack_listing||
  1251.         !listonly)?18:3) ){
  1252.         EventRecord        myEvent;
  1253.         if((check_ev_timing&1) || !OSEventAvail(everyEvent,&myEvent))
  1254.             return;
  1255.         }
  1256.     check_ev_timing=0;
  1257.  
  1258.     sto_lavorando=pausable=true;
  1259.  
  1260.     /* what follows is the body of MainEvent, with an extra call in order to ignore
  1261.     all the events which are not urgent */
  1262.  
  1263.     if(get_event(&myEvent)){
  1264.         if(check_filter(&myEvent)){
  1265.             if(my_event_filter!=NULL) (*my_event_filter)(&myEvent);
  1266.             handle_event(&myEvent);
  1267.             }
  1268.         }
  1269.     sto_lavorando=pausable=false;
  1270.     }
  1271. if(last_selection==menuItemMess(fileID,fmPause))
  1272.     handle_pause();
  1273. accept_abort_command();
  1274. }
  1275.  
  1276. short check_error_and_events()
  1277. {
  1278. /* in theory it's:
  1279. if(check_error()) return -1;
  1280. check_events();
  1281. return 0;
  1282. in practice, it was extended to transform a "missing disk" error to a pause,
  1283. so you (and we) won't lose your work for an unwanted eject (it happened to us
  1284. for a 4Megabytes file, filling 3 disks, and we had to start again after
  1285. half an hour of work in background). But the caller must read the sector again,
  1286. hence a new return code of 1
  1287. */
  1288. if(err_code!=-65){
  1289.     if(check_error()) return -1;
  1290.     check_events();
  1291.     return 0;
  1292.     }
  1293. else{
  1294.     beep_in_foreground();
  1295.     start_of_line();
  1296.     printf(in_Italia?"Disco assente, pausa forzata\n":"Missing disk, a pause was forced\n");
  1297.     last_selection=menuItemMess(fileID,fmPause);
  1298.     check_events();
  1299.     return 1;
  1300.     }
  1301. }
  1302.  
  1303. void accept_abort_command()
  1304. {
  1305. if(last_selection == menuItemMess(fileID,fmAbort)){
  1306.     if(fase==reading_disk&&!listonly||fase==writing_disk||fase==selected_reading||fase==paused){
  1307.         if(dialogo_abort()==2){
  1308.             last_selection=0;
  1309.             return;
  1310.             }
  1311.         }
  1312.     one_empty_line();
  1313.     error_message(in_Italia?"Comando abortito\n":"Command aborted\n");
  1314.     }
  1315. }
  1316.  
  1317. Boolean is_abort_command()
  1318. /* external routines must not know how I receive the Abort command,
  1319. but they must be able to know when they must abort themselves */
  1320. {
  1321. return last_selection == menuItemMess(fileID,fmAbort);
  1322. }
  1323.  
  1324. Boolean is_pause_command()
  1325. {
  1326. return last_selection == menuItemMess(fileID,fmPause);
  1327. }
  1328.  
  1329. /****************** gestione dialogo di inserzione *********/
  1330.  
  1331. short filter_insert(EventRecord*);
  1332. static short filter_insert(theEvent)
  1333. EventRecord*theEvent;
  1334. {
  1335. if(theEvent->what==diskEvt){
  1336.     drive_number=loword(theEvent->message);
  1337.  
  1338.     if(drive_number<=last_drive){
  1339.         /*FlushVol (PNS,drive_number);*/
  1340.         UnmountVol (NULL,drive_number); /* smonta qualunque 
  1341.         cosa si trovasse in precedenza in quel drive, e il disco stesso se è stato
  1342.         montato: inutile guardare al codice di errore ritornato
  1343.         -- the Finder often mounts even a tar archive, if it was formatted on a Mac
  1344.         (see de_Mac_ize in tar.c): anyway, it must not be mounted if I want to use 
  1345.         it without being disturbed by the Finder; the returned error code may be 
  1346.         ignored, I don't worry to call this only when it was mounted...
  1347.         */
  1348.         return -1;
  1349.         }
  1350.     }
  1351. else if(drive_number)    /* the user may call the about_box, but about_box does
  1352.     not delay the handling of disk insertions (as options_box does), hence it's
  1353.     possible that the disk insertion event was handled by unexpected_disk_insertion */
  1354.     return -1;
  1355. return 0;
  1356. }
  1357.  
  1358. /************* aspetta inserzione **************/
  1359.  
  1360. short aspetta_inserzione(message,examine_disk)
  1361. /* if a file or disk is already open, return immediately; otherwise,
  1362. present the disk insertion dialog and update all the status informations
  1363. about the current disk
  1364. returns
  1365. -1 or a error code <0: some error occurred, or the user clicked on Cancel
  1366. 0: disk correctly inserted
  1367. */
  1368. char*message;
  1369. Boolean examine_disk;
  1370. {
  1371. static Point wPos={-1,-1};
  1372. static char*titoli[]={"\pAnnulla","\pEsamina il disco"};
  1373. short inPlace;
  1374. short i;
  1375.  
  1376. if(drive_number!=0){
  1377.     if(testa_stato(&inPlace,0)==0){
  1378.         if(inPlace){
  1379.             if(di.is_not_initialized)
  1380.                 printf(in_Italia?"Disco non inizializzato\n":"This disk is not initialized\n");
  1381.             return 0;
  1382.             }
  1383.         }
  1384.     else
  1385.         drive_number=0;
  1386.     }
  1387. else if(file_aperto){
  1388.     di.is_not_initialized=false;
  1389.     di.os=unknown_os;
  1390.     di.disk_code=noMacDskErr;
  1391.     return 0;
  1392.     }
  1393.  
  1394. if(preferred_drive){
  1395. /* if there only one disk drive, or only one is a SuperDrive, eject anything
  1396. was currently in that drive, since it's the only place where the user may insert
  1397. the requested disk. But don't do that if a disk insertion on that drive has just
  1398. happened
  1399. */
  1400.     EventRecord event;
  1401.  
  1402.     drive_number=preferred_drive;
  1403.  
  1404.     if ( !OSEventAvail(diskMask,&event) || drive_number!=loword(event.message)){
  1405.         /*FlushVol (PNS,drive_number);*/
  1406.         UnmountVol (NULL,drive_number);    /* inutile guardare al codice di errore ritornato */
  1407.         diskEject();
  1408.         }
  1409.     }
  1410.  
  1411. i=semimodalDialog(examine_disk?144:138,&wPos,filter_insert,&titoli,examine_disk?2:1,
  1412.     message,in_Italia?"\p\r\rin un disk drive":"\p\r\rin a floppy disk drive",NULL,
  1413.     teJustCenter,fase==ricevuto_comando||fase==initializing,
  1414.     examine_disk?set_exam_checkbox:NULL);
  1415.  
  1416. if(i==-1){
  1417.     if(testa_stato(&inPlace,1)){
  1418.         if(fase==initializing) return 0;
  1419.         diskEject();
  1420.         return -1;
  1421.         }
  1422.     return 0;    /* disco inserito OK */
  1423.     }
  1424.  
  1425. return -1;    /* i==1, there are no other possible cases */
  1426. }
  1427.  
  1428. /************************************/
  1429.  
  1430. void esamina_disco()            /* examine a disk */
  1431. {
  1432. /* save global variables which must not be altered, but are used by
  1433. some routines which I must call now */
  1434. enum tipo_fase oldfase=fase;
  1435. unsigned char savePrevFormat=previousFormat;
  1436. Boolean savebar_archive=bar_archive;
  1437. char savebuffer[512];
  1438. enum formats j;
  1439. mcopy(savebuffer,disk_buffer,512);
  1440.  
  1441. fase=reading_disk;    /* otherwise abort could be disabled */
  1442. listonly=1;        /* don't use buffering */
  1443. /* I'm in a very peculiar situation, I must do a rather complex operation,
  1444. requiring a number of function calls, but this operation is launched from
  1445. within a very low level of another high level operation (disk_buffer is
  1446. full, etc.). Hence, I must pay a lot of attention, suntar contains a lot
  1447. of global variables and most of them can't be altered in this moment.
  1448.  Furthermore, this operation could raise an error, but I can't allow 
  1449. that raise_error be called, since it resets a lot of global variables,
  1450. closes open files...
  1451.  The only reasonable solution is not to use the standard way of doing a
  1452. List, but recreating it by using low-level functions (low enough that I can
  1453. carefully examine all their instructions, and the instructions of the
  1454. functions called by them) so that I can be sure that raise_error is not
  1455. called, and I may be sure that the list of altered global variables is
  1456. accurate.
  1457.  I wanted that the Abort command were active during this List (aborting
  1458. the List and not anything else), hence I must handle it before it causes
  1459. a raise_error, and that requires not using check_events too.
  1460. */
  1461.  
  1462. j=identify_format();    /* it can't cause a call to raise_error */
  1463. if(j==tar_format||j==bar_format){
  1464.     bar_archive= j==bar_format;
  1465.     list_conciso();
  1466.     one_empty_line();
  1467.     }
  1468. else if (di.os==mac_MFS || di.os==mac_HFS){    /* Try to print some informations,
  1469.         but without mounting the disk */
  1470.     leggi_settore(2,disk_buffer);
  1471.     if(err_code==0){
  1472.         static char *tot_files[2]={"Total files=%ld ","Numero totale di files=%ld "};
  1473.         disable_autoflush(2);
  1474.         printf("Volume %P (%ld KB ",&disk_buffer[36],
  1475.            ((*(unsigned short*)&disk_buffer[34]) * (*(long*)&disk_buffer[20]) )>>10 );
  1476.         printf(in_Italia?"disponibili)\n":"free)\n");
  1477.         if(di.os==mac_HFS){
  1478.             printf(tot_files[in_Italia?1:0],
  1479.              (long) ( max(1L,*(long*)&disk_buffer[84]) -1)  );    /* do NOT count the
  1480.                      Desktop file, but if it does not exist do not declare -1 files */
  1481.             printf(in_Italia?"(di cui %u nella radice)":"(%u in root)",
  1482.                 max(1,*(unsigned short*)&disk_buffer[12]) -1 );
  1483.             printf(in_Italia?" numero cartelle totali=%ld":" total folders=%ld ",*(long*)&disk_buffer[88]);
  1484.             }
  1485.         else
  1486.             printf(tot_files[in_Italia?1:0],
  1487.              (long) ( max(1,*(unsigned short*)&disk_buffer[12]) -1)  );
  1488.         printf("\n");
  1489.         enable_autoflush();
  1490.         }
  1491.     }
  1492. bar_archive=savebar_archive;
  1493. previousFormat=savePrevFormat;
  1494. mcopy(disk_buffer,savebuffer,512);
  1495. fase=oldfase;
  1496. }
  1497.  
  1498. void list_conciso()    /* used by the "examine a disk" button */
  1499. {
  1500. long length;
  1501. sector_t s_n=0;
  1502.  
  1503. disable_autoflush(1);
  1504.  
  1505. printf(in_Italia?"Contenuto attuale del disco:\n":"Current content of this disk:\n");
  1506. if(bar_archive){
  1507.     short f_n;
  1508.     length=untar_number( ((barh_type*)disk_buffer)->size,-1);
  1509.     f_n=untar_dec_number( ((barh_type*)disk_buffer)->volume_num,-1);
  1510.     
  1511.     if(length==-1 || f_n==-1){
  1512.         printf(in_Italia?"Testata non in formato bar !\n":
  1513.               "Error: not a bar header !\n");
  1514.           enable_autoflush();
  1515.           return;
  1516.           }
  1517.     s_n = (length+1023)>>9;
  1518.     printf(in_Italia?"Disco numero %d":"Disk number %d",f_n);
  1519.     print_if_string(in_Italia?" dell\'archivio %s":" of the archive %s",
  1520.         ((barh_type*)disk_buffer)->name,100);
  1521.     printf("\n");
  1522.     }
  1523.  
  1524. while(s_n<sectors_on_floppy){
  1525.     register unsigned char linkflag;
  1526.  
  1527.     if(list_events()){
  1528.         last_selection=0;
  1529.         one_empty_line();
  1530.         printf(in_Italia?"List interrotto\n":"List aborted\n");
  1531.         enable_autoflush();
  1532.         return;
  1533.         }
  1534.     leggi_settore(s_n,disk_buffer);
  1535.     if(check_error()){
  1536.         if(err_code==-65) drive_number=0;    /* missing disk... */
  1537.         enable_autoflush();
  1538.         return;
  1539.         }
  1540.  
  1541.     if(check_all_zero(disk_buffer)){
  1542.         if(s_n==0||(bar_archive||hasVheader)&&s_n==1)
  1543.             printf(in_Italia?"Disco vuoto\n":"No files on disk\n");
  1544.         else
  1545.             printf(in_Italia?"Fine archivio\n":"End of archive\n");
  1546.         enable_autoflush();
  1547.         return;
  1548.         }
  1549.     linkflag= get_linkflag(&length,-1);
  1550.     if(linkflag==0xFF){
  1551.          printf(in_Italia?"Testata non in formato %car !\n":
  1552.               "Error: not a %car header !\n",bar_archive ? 'b' : 't');
  1553.         enable_autoflush();
  1554.          return;
  1555.         }
  1556.     if(linkflag!='1'&&linkflag!='2'){
  1557.         if(linkflag=='M'){
  1558.             if(!bar_archive) printf(in_Italia?"Parte del file %s\n":
  1559.                 "Part of file %s\n",((tarh_type*)disk_buffer)->name);
  1560.             }
  1561.         else if(linkflag=='V'){
  1562.             if(!bar_archive) printf(in_Italia?"Il nome del disco è %s\n":
  1563.                 "The disk name is %s\n",((tarh_type*)disk_buffer)->name);
  1564.             }
  1565.         else
  1566.             print_info(bar_archive ? ((barh_type*)disk_buffer)->name :
  1567.                 ((tarh_type*)disk_buffer)->name,length);
  1568.         }
  1569.     s_n += (length+1023)/512;
  1570.     }
  1571. printf(in_Italia?"Continua su un altro disco\n":"Continuing on another disk\n");
  1572. enable_autoflush();
  1573. }
  1574.  
  1575. static Boolean list_events()
  1576. /* replaces check_events during list_conciso */
  1577. {
  1578. EventRecord        myEvent;
  1579.  
  1580. ++check_ev_timing;
  1581. if( check_ev_timing<3) return false;
  1582. check_ev_timing=0;
  1583.  
  1584. sto_lavorando=true;
  1585.  
  1586. if(get_event(&myEvent)){
  1587.     if(check_filter(&myEvent)){
  1588.         if(my_event_filter!=NULL) (*my_event_filter)(&myEvent);
  1589.         handle_event(&myEvent);
  1590.         }
  1591.     }
  1592. sto_lavorando=false;
  1593.  
  1594. return last_selection == menuItemMess(fileID,fmAbort);
  1595. }
  1596.  
  1597. /*************************************************/
  1598.  
  1599. void check_foreground()
  1600. {
  1601. /* to be called before interacting with the user when I could be 
  1602. running in background: if I am, call the Notification Manager to alert
  1603. the user and wait for him/her to bring this application to foreground
  1604. */
  1605.  
  1606. if(gInBackground){
  1607.     NMRec my_notif_rec;
  1608.  
  1609.     my_notif_rec.qType=8;
  1610.     my_notif_rec.nmMark=1;
  1611. #ifndef THINK_C_5
  1612.     my_notif_rec.nmSIcon=GetResource ('SICN',128);
  1613. #else
  1614.     /* with another version of header files, it's */
  1615.     my_notif_rec.nmIcon=GetResource ('SICN',128);
  1616. #endif
  1617.     my_notif_rec.nmSound=(void*)-1;
  1618.     my_notif_rec.nmStr=NULL;
  1619.     my_notif_rec.nmResp=NULL;
  1620.     NMInstall(&my_notif_rec);
  1621.     while(gInBackground)
  1622.         MainEvent();
  1623.     NMRemove(&my_notif_rec);
  1624. #ifndef THINK_C_5
  1625.     ReleaseResource(my_notif_rec.nmSIcon);
  1626. #else
  1627.     ReleaseResource(my_notif_rec.nmIcon);
  1628. #endif
  1629.     }
  1630. settori_passati=0;
  1631.  
  1632. }
  1633.  
  1634. void beep_in_foreground()
  1635. {
  1636. if(gInBackground)
  1637.     check_foreground();        /* which does a beep */
  1638. else
  1639.     SysBeep(5);
  1640. }
  1641.  
  1642.  
  1643. /***********************/
  1644.  
  1645. void update_about_box(EventRecord*);
  1646. static void update_about_box(theEvent)
  1647. EventRecord *theEvent;
  1648. {
  1649. WindowPtr theWindow=(WindowPtr)theEvent->message;
  1650. static Rect
  1651.     boundsR1={10,105,30,475},
  1652.     boundsR2={40,130,140,475},
  1653.     boundsR3={148,5,285,300},
  1654.     dstRect1={5,5,129,129},
  1655.     dstRect2={148,288,258,476};
  1656. Handle h;
  1657. GrafPtr    savePort;
  1658. char*p;
  1659.  
  1660. GetPort( &savePort );
  1661. SetPort(theWindow);
  1662. BeginUpdate( theWindow );
  1663.  
  1664. TextFont(3);
  1665. TextSize(12);
  1666. p="suntar 1.3.2";
  1667.  
  1668. TextBox(p,(long)strlen(p),&boundsR1,teJustCenter);
  1669. TextFont(4);
  1670. TextSize(9);
  1671.  
  1672. if(in_Italia) p=
  1673. "Suntar è il mezzo più semplice ed economico di comunicare\r\
  1674. dati tra un Macintosh (dotato di SuperDrive) e un sistema\r\
  1675. UNIX (con un drive per floppy disk da 3,5 pollici):\r\
  1676. legge e scrive dischetti in formato tar UNIX, convertendo\r\
  1677. automaticamente i files di testo e i formati MacBinary e\r\
  1678. BinHex 4.0, usati negli archivi di pubblico dominio per\r\
  1679. immagazzinare files Macintosh in files UNIX.\r\
  1680. Sotto System 7, puoi usare gli aiuti a fumetti.";
  1681. else
  1682. p=
  1683. "Suntar is the simplest and cheapest way to communicate\r\
  1684. data between a Macintosh (with a SuperDrive) and a UNIX\r\
  1685. machine (with a 3.5 inch floppy disk drive): it reads\r\
  1686. and writes disks in the UNIX tar format, automatically\r\
  1687. converting plain text files and the MacBinary and\r\
  1688. BinHex 4.0 formats, used in public domain archives to\r\
  1689. store Macintosh files in UNIX files.\r\
  1690. Under System 7, help balloons are available.";
  1691.  
  1692. TextBox(p,(long)strlen(p),&boundsR2,teJustRight);
  1693.  
  1694. if(in_Italia) p=
  1695. "suntar è un programma freeware\r\
  1696. © 1991-92 Sauro e Gabriele Speranza\r\
  1697. Indirizzo: Sauro Speranza via Cappuccini 18\r\
  1698.            40026 Imola (Bo)\r\
  1699. E-mail: speranza@cirfid.unibo.it\r\
  1700. oppure: speranza@cs.unibo.it\r\
  1701. Porzioni del programma sono © Gail Zacharias,\r\
  1702. Symantec, Apple Computer, Allan Weber.\r\
  1703. Scritto in Think C (© 1989-91\r\
  1704.      Symantec Corporation)";
  1705. else p=
  1706. "suntar is a freeware program\r\
  1707. © 1991-92 Sauro and Gabriele Speranza\r\
  1708. Address: Sauro Speranza via Cappuccini 18\r\
  1709.          40026 Imola Italy\r\
  1710. E-mail: speranza@cirfid.unibo.it\r\
  1711.     or: speranza@cs.unibo.it\r\
  1712. Portions of suntar are © Gail Zacharias,\r\
  1713. Symantec, Apple Computer, Allan Weber.\r\
  1714. Written in Think C (© 1989-91\r\
  1715.      Symantec Corporation)";
  1716.  
  1717. TextBox(p,(long)strlen(p),&boundsR3,teJustLeft);
  1718.  
  1719. h=GetResource ('PICT',128);
  1720. HLock(h);
  1721. DrawPicture (h, &dstRect1);
  1722. ReleaseResource(h);
  1723. h=GetResource ('PICT',129);
  1724. HLock(h);
  1725. DrawPicture (h, &dstRect2);
  1726. ReleaseResource(h);
  1727.  
  1728. EndUpdate( theWindow );
  1729. SetPort (savePort);
  1730.  
  1731. }
  1732.  
  1733. void about_box()
  1734. {
  1735. static Rect
  1736.     winRect={0,0,265,480};
  1737. WindowPtr theWindow;
  1738. short stato=0;
  1739. EventRecord        myEvent;
  1740. enum tipo_fase old_fase=fase;
  1741.  
  1742. flush_all();
  1743. PositionDialog(&winRect);
  1744. theWindow=NewWindow( NULL, &winRect, PNS, 1, dBoxProc, (WindowPtr)-1L, 0, (long)-1);
  1745. ((WindowPeek)theWindow)->refCon= -3;
  1746.  
  1747. install_handlers(theWindow, update_about_box, NULL);
  1748. while(stato!=2){
  1749.     sto_lavorando=false;    /* cursor shape and delay for WaitNextEvent... */
  1750.     fase=paused;            /* for unexpected_disk_insertion */
  1751.     if(get_event(&myEvent)){
  1752.         if(myEvent.what==diskEvt){
  1753.             short olddrive=drive_number;
  1754.             unexpected_disk_insertion(myEvent.message);
  1755.             if(olddrive!=drive_number) break;
  1756.             }
  1757.         else if(myEvent.what==mouseDown)
  1758.             stato=1;
  1759.         else if(stato==1&&myEvent.what==mouseUp)
  1760.             stato=2;
  1761.         /* all other events are ignored: that's anyway a progress upon the 1.1 version, 
  1762.         which never called GetNextEvent during the about box (background tasks and 
  1763.         even screen savers were disabled...) */
  1764.         }
  1765.     }
  1766.  
  1767. remove_handlers(theWindow);
  1768. DisposeWindow(theWindow);
  1769. fase=old_fase;
  1770. /*Riattiva();*/
  1771. }
  1772.  
  1773.  
  1774. /************* check all zero **********/
  1775.  
  1776. Boolean check_all_zero(buffer)
  1777. char *buffer;
  1778. {
  1779. register short    i=512/sizeof(long);
  1780. register long    n_or=0;
  1781. register long*    p= (long*) &buffer[0];
  1782.  
  1783. while(--i>=0 &&  (n_or|= *p++) ==0L)
  1784.     ;
  1785. return n_or==0L;
  1786. }
  1787.  
  1788. /************************/
  1789.  
  1790. void print_info(name,length)
  1791. char *name;
  1792. long length;
  1793. {
  1794. if(name[strlen(name)-1]=='/')
  1795.     printf("Directory %s\n",name);
  1796. else
  1797.     printf("File %s (%ld bytes)\n",name,length);
  1798. }
  1799.  
  1800. /*****************************/
  1801.  
  1802. void raise_error()
  1803. {
  1804. /* prima di riprendere, chiamo tutte le routine di "cleanup", che ovviamente
  1805. se non c'è niente da chiudere ritornano senza fare niente
  1806. -- in suntar, all high level routines must use a setjmp to handle
  1807. recovering after an error. All permanent entities (variables, files, windows)
  1808. which need to be closed or restored to the normal state must be associated to
  1809. a clean-up routine (which does nothing if no clean-up is needed) and that
  1810. routine must be called here (beware, there's also a raise_hqx_error, which
  1811. aborts the extraction of the current file but not the command)
  1812. */
  1813. SetCursor(&waitCursor);    /* closing files may flush the disk cache, and that
  1814.             may take several seconds (at least, it was so before suntar had
  1815.             its own caching) */
  1816. deall_tree();
  1817.  
  1818. if(drive_number && dirty_buffers()){
  1819.     short refnum;
  1820.     long space;
  1821.     if( GetVInfo (drive_number, disk_buffer, &refnum,&space) == nsvErr ){
  1822.         /* no such volume: a non-Mac disk is not mounted hence...*/
  1823.         flush_buffers();
  1824.         }
  1825.     else
  1826.         invalid_buffers();
  1827.     }
  1828.  
  1829. my_event_filter=NULL;
  1830. if(fase==writing_disk || last_selection!=menuItemMess(fileID,fmAbort)){
  1831.     check_and_eject();
  1832.     chiudi_archivio();
  1833.     }
  1834. last_selection=0;
  1835. sto_lavorando=pausable=false;
  1836. close_input_files();
  1837. close_or_del_out_file();
  1838. close_info_file();
  1839. enable_autoflush();
  1840. close_semimodal();
  1841. FlushEvents( everyEvent, 0 );
  1842. longjmp(main_loop,-1);
  1843. }
  1844.  
  1845. void error_message(p)
  1846. char *p;
  1847. {
  1848. start_of_line();
  1849. printf(p);
  1850. raise_error();
  1851. }
  1852.  
  1853.  
  1854. void error_message_1(p,n)
  1855. char *p;
  1856. int n;
  1857. {
  1858. start_of_line();
  1859. printf(p,n);
  1860. raise_error();
  1861. }
  1862.  
  1863. /************************/
  1864. short check_error()
  1865. {
  1866. /* da chiamare esclusivamente dopo leggi_settore
  1867. -- to be called after leggi_settore */
  1868. if(err_code){
  1869. /* e se invece riprovassi a leggere ? Non è che il disk driver ritenti già lui? */
  1870.     disk_error_message();
  1871.     if(!ignore_errors){
  1872.         OSErr olderr=err_code;
  1873.         diskEject();
  1874.         err_code=olderr;
  1875.         return -1;
  1876.         }
  1877.     }
  1878. return 0;
  1879. }
  1880.  
  1881. void disk_error_message()
  1882. {
  1883.     start_of_line();
  1884.     if(err_code==-39 || file_aperto && err_code==-81)
  1885.         printf(in_Italia?"Fine del file prematura\n":"Error: unexpected end of file\n");
  1886.     else if(err_code==-65)
  1887.         printf(in_Italia?"Errore: disco assente\n" : "Error: missing disk\n");
  1888.     else if(err_code<=-66 && err_code>=-71)
  1889.         printf(in_Italia?"Settore illeggibile (errore %d)\n": 
  1890.             "Unreadable sector (error code %d)\n",err_code);
  1891.     else if(err_code<=-72 && err_code>=-73)
  1892.         printf(in_Italia?"Settore difettoso (errore %d)\n": 
  1893.             "Defective sector (error code %d)\n",err_code);
  1894.     else
  1895.         printf(in_Italia?"Errore di lettura n° %d\n":"Disk read error %d\n",err_code);
  1896. }
  1897.  
  1898. void write_error_message()
  1899. /* to be called when mac_fwrite fails */
  1900. {
  1901. if(err_code==dskFulErr)
  1902.     error_message(in_Italia?"Errore: disco pieno\n":"Error: disk full\n");
  1903. else if(err_code==ioErr)
  1904.     error_message("I/O error during file write\n");
  1905. else if(err_code==wrPermErr)
  1906.     error_message("Error: no write permission\n");
  1907. else
  1908.     error_message_1("File write error %d\n",err_code);
  1909. }
  1910.  
  1911. /***********************************************************************/
  1912.  
  1913. void hacking(command)
  1914. short command;
  1915. /* handles all the commands in the Special menu: mainly for historical reasons
  1916. (suntar 1.0 was rather modal) I preferred to loop internally while commands are 
  1917. from this menu rather than returning to the main loop after executing
  1918. the first command
  1919. */
  1920.  
  1921. {
  1922. /* visto che i comandi del menù Special sono attivi se e solo se lo sono quelli
  1923. del menù file avrebbe senso eseguire un solo comando e ritornare, preferisco 
  1924. ciclare anche qui dentro perché così è più facile gestire il comando Again */
  1925.  
  1926.  
  1927. short inPlace;
  1928. register short i;
  1929. Boolean sect_n_valid;
  1930. Boolean out_f_open=false;
  1931. sector_t default_sect_n=0;
  1932. short outputFile;
  1933. static unsigned char messIta[]="\pInserisci il disco di prova",
  1934.     messIng[]="\pInsert the test disk",
  1935.     mess_wrprot[]="Write protected disk !\n";
  1936.  
  1937. next_header_for_AIX=-1;
  1938. again_command=0;
  1939. if(setjmp(main_loop)<0){
  1940.     if(out_f_open) FSClose(outputFile);
  1941.     if(again_command!=hmList || !drive_number)
  1942.         return;            /* il disco è stato espulso, non ha senso restare qui dentro;
  1943.                         non è detto però, forse a volte non espello ! */
  1944.     command=0;
  1945.     }
  1946.  
  1947. if(aspetta_inserzione(in_Italia?messIta:messIng,false))
  1948.     return;
  1949.  
  1950. for(;;){
  1951.     if(command==0){
  1952.         fase=non_faccio_nulla;
  1953.         close_all_open_WD();
  1954.         check_ev_timing=120;
  1955.         flush_buffers();
  1956.         enable_autoflush();
  1957.         last_selection=0;
  1958.         while(last_selection==0){
  1959.             MainEvent();
  1960.             if(!expert_mode) return;
  1961.             }
  1962.         if(again_command==hmView && (loword(last_selection)==hmView ||
  1963.            loword(last_selection)==hmAgain) && default_sect_n<sectors_on_floppy-1) 
  1964.                 default_sect_n++;    /* tipicamente io guardo
  1965.                    il settore prima di farci sopra un clear o read, per cui voglio un
  1966.                    autoincremento solo se il comando resta view
  1967.                    -- I usually view a sector just before clearing or untar-ring, hence
  1968.                    I want auto-increment only if the following command is another View */
  1969.         command=loword(last_selection);
  1970.         fase=ricevuto_comando;
  1971.         if(hiword(last_selection)==fileID)
  1972.             return;        /* non tocca a me gestirlo */
  1973.         last_selection=0;
  1974.         if(sect_n_valid=(command==hmAgain)){
  1975.             command=again_command;
  1976.             if(command==hmList){
  1977.                 diskEject();    /* non avrebbe senso farlo due
  1978.                     volte sullo stesso disco, ma ha senso farlo su più dischi di fila
  1979.                     -- Do it again used on Expert list means do it on another disk,
  1980.                     hence the current disk must be ejected */
  1981.                 if(aspetta_inserzione(in_Italia?messIta:messIng,false))
  1982.                     return;
  1983.                 }
  1984.             }
  1985.         again_command=0;
  1986.         }
  1987.     else
  1988.         sect_n_valid=false;
  1989.  
  1990.     switch(command){
  1991.         case hmList:
  1992.             {
  1993.             enum formats fmt;
  1994.             if(drive_number) /* solo su disco, non su file */
  1995.                 again_command=hmList;
  1996.             if(next_header_for_AIX!=-1 && tar_version==tar_AIX)
  1997.                 fase=hack_listing;    /* so identify_format doesn not print
  1998.                         its "unknown format" message */
  1999.             one_empty_line();
  2000.             fmt = identify_format();    /* che legge in disk_buffer il settore 0
  2001.                             -- which leaves a copy of sector 0 in disk_buffer */
  2002.             if(next_header_for_AIX!=-1 && tar_version==tar_AIX && fmt==unknown_format){
  2003.                 /* printf("sn=%ld\n",next_header_for_AIX); */
  2004.                 if(next_header_for_AIX < sectors_on_floppy){
  2005.                     leggi_settore(next_header_for_AIX,&tarh);
  2006.                     if(check_all_zero(&tarh)){
  2007.                         print_sector_n(next_header_for_AIX);
  2008.                         printf("End of Archive (dangerous, can\'t check it\'s the right disk)\n");
  2009.                         break;        /*save the value of next_header_for_AIX */
  2010.                         }
  2011.                     else if(untar_number(tarh.size,-1) != -1 &&
  2012.                             untar_checksum(&tarh,-1,false) != -2)
  2013.                         fmt=tar_format;
  2014.                     else{
  2015.                         printf("Unknown format (maybe wrong disk)\n");
  2016.                         break;
  2017.                         }
  2018.                     }
  2019.                 else{
  2020.                     printf("No file starts here (dangerous, can\'t check it\'s the right disk)\n");
  2021.                     next_header_for_AIX-=sectors_on_floppy;
  2022.                     break;
  2023.                     }
  2024.                 }
  2025.             else
  2026.                 next_header_for_AIX=-1;
  2027.  
  2028.             fase=hack_listing;
  2029.             if(fmt==bar_format){
  2030.                 short n;
  2031.                 one_empty_line();
  2032.                 printf(START_READ);
  2033.                 if(my_atoi(((barh_type*)disk_buffer)->volume_num,&n)!=0)
  2034.                     printf("No sequence number\n");
  2035.                 else
  2036.                     stampa_info_bar(n);
  2037.                 listonly=1;
  2038.                 my_unbar();        /* che in caso di fase==hack_listing si comporta diversamente
  2039.                                 dal solito per il cambio disco, e stampa più informazioni
  2040.                                 -- which, when fase==hack_listing, behaves differently
  2041.                                 than when called by a List command */
  2042.                 }
  2043.             else if(fmt==tar_format){
  2044.                 one_empty_line();
  2045.                 printf(START_READ);
  2046.                 listonly=1;
  2047.                 my_untar();
  2048.                 }
  2049.             next_header_for_AIX=-1;
  2050.             }
  2051.             check_foreground();
  2052.             break;
  2053.         case hmClear:    /* clear sector */
  2054.         case hmOverwrite:
  2055.             one_empty_line();
  2056.             if(is_wrprot()){
  2057.                 printf(mess_wrprot);
  2058.                 }
  2059.             else{
  2060.                 if(command==hmClear){
  2061.                     printf("Clearing the sector will erase its previous content.\n");
  2062.                     printf(
  2063. "If it was an header, List, Extract and Append will see it as end of the archive\n");
  2064.                     sect_n=default_sect_n;
  2065.                     }
  2066.                 else{
  2067.                     printf("The previous content will be lost\nstart ");
  2068.                     sect_n=0;
  2069.                     } 
  2070.                 fase=reading_sect_n;
  2071.                 if(read_sect_n(§_n)==noErr){
  2072.                     if(command==hmClear){
  2073.                         fillmem(disk_buffer, 0, 512);
  2074.                         scrivi_settore(sect_n,disk_buffer);
  2075.                         if(err_code) printf(diskWriteErrMsg,err_code);
  2076.                         }
  2077.                     else{
  2078.                         overwrite_sectors();
  2079.                         printf(DONE);
  2080.                         check_foreground();
  2081.                         }
  2082.                     default_sect_n=sect_n;
  2083.                     }
  2084.                 }
  2085.             break;
  2086.         case hmView:        /* view sector */
  2087.             fase=reading_sect_n;
  2088.             one_empty_line();
  2089.             if(sect_n_valid)
  2090.                 printf("View sector %ld\n",(long)sect_n);
  2091.             else{
  2092.                 sect_n=default_sect_n;
  2093.                 sect_n_valid= read_sect_n(§_n)==0;
  2094.                 }
  2095.             if(sect_n_valid){
  2096.                 fillmem(disk_buffer, 0, 512);
  2097.                 read_sectors(sect_n,&disk_buffer,1);
  2098.                 if(err_code){
  2099.                     beep_in_foreground();
  2100.                     disk_error_message();
  2101.                     }
  2102.                 stampa_buffer(sect_n,disk_buffer);
  2103.                 again_command=command;
  2104.                 default_sect_n=sect_n;
  2105.                 if(sect_n<sectors_on_floppy-1) sect_n++;
  2106.                 }
  2107.             break;
  2108.         case hmSave:
  2109.             {sector_t sect_finale;
  2110.             my_SF_Put("\pSave as:","\psectors");
  2111.             if(!reply.good) break;
  2112.  
  2113.             i=new_text_file(&outputFile);
  2114.             if(i!=noErr) break;
  2115.             out_f_open=true;
  2116.             sect_n=default_sect_n;
  2117.             fase=reading_sect_n;
  2118.             one_empty_line();
  2119.             if((printf("start "),read_sect_n(§_n)==0) && 
  2120.                (sect_finale=sect_n,printf("end "),read_sect_n(§_finale)==0) ){
  2121.  
  2122.                 fase=reading_disk;
  2123.                 do{
  2124.                     check_events();
  2125.                     leggi_settore(sect_n,&disk_buffer);
  2126.                     if(check_error()) raise_error();
  2127.                     if(mac_fwrite(disk_buffer, 512, outputFile)<=0){
  2128.                         beep_in_foreground();
  2129.                         write_error_message();
  2130.                         }
  2131.                     sect_n++;
  2132.                     }
  2133.                 while(sect_n<=sect_finale);
  2134.                 }
  2135.             FSClose(outputFile);
  2136.             printf(DONE);
  2137.             check_foreground();
  2138.             out_f_open=false;
  2139.             }
  2140.             break;
  2141.         case hmFind:
  2142.             {short err_n=0;
  2143.             long exp_check;
  2144.             Boolean stampato=false;
  2145.             one_empty_line();
  2146.             fase=reading_disk;
  2147.             listonly=0;        /* full buffering... */
  2148.             for(sect_n=0;sect_n<sectors_on_floppy;sect_n++){
  2149.                 check_events();
  2150.                 leggi_settore(sect_n,&disk_buffer);
  2151.                 if(err_code!=noErr){
  2152.                     printf("sector %ld could not be read\n",(long)sect_n);
  2153.                     if(++err_n>max(20,(short)(sect_n/8))){
  2154.                         beep_in_foreground();
  2155.                         error_message("Too many errors, search aborted\n");
  2156.                         }
  2157.                     }
  2158.                 else if(untar_number(((struct tarh_type*)disk_buffer)->size,-1) != -1 &&
  2159.                         untar_checksum(&disk_buffer,-1,false) == 0){
  2160.                     disk_buffer[99]=0;
  2161.                     disable_autoflush(2);
  2162.                     printf("tar ");
  2163.                     print_sector_n(sect_n);
  2164.                     if(((struct tarh_type*)disk_buffer)->linkflag=='V')
  2165.                         printf("Volume header: ");
  2166.                     if(((struct tarh_type*)disk_buffer)->linkflag=='M')
  2167.                         printf("Continuation: ");
  2168.                     printf("%s\n",disk_buffer);
  2169.                     enable_autoflush();
  2170.                     stampato=true;
  2171.                     }
  2172.                 else if(sect_n!=0&&untar_number(((barh_type*)disk_buffer)->size,-1) !=-1 &&
  2173.                         unbar_checksum(&disk_buffer,-1,&exp_check) == 0 ){
  2174.                     ((barh_type*)disk_buffer)->name[99]=0;
  2175.                     printf("bar ");
  2176.                     print_sector_n(sect_n);
  2177.                     printf(" %s\n",((barh_type*)disk_buffer)->name);
  2178.                     stampato=true;
  2179.                     }
  2180.                 }
  2181.             if(!stampato) printf("No headers found\n");
  2182.             printf(DONE);
  2183.             check_foreground();
  2184.             }
  2185.             break;
  2186.         case hmUntar:
  2187.         case hmUnbar:
  2188.             fase=reading_sect_n;
  2189.             one_empty_line();
  2190.  
  2191.             if(sect_n_valid)
  2192.                 printf("Un%car at sector %ld\n",((command==hmUntar)?'t':'b'),(long)sect_n);
  2193.             else{
  2194.                 sect_n=default_sect_n;
  2195.                 sect_n_valid= read_sect_n(§_n)==0;    /* come sopra */
  2196.                 }
  2197.             if(sect_n_valid){
  2198.                 leggi_settore(sect_n,&disk_buffer);
  2199.                 if(err_code)
  2200.                     disk_error_message();
  2201.  
  2202.                 else if(check_all_zero(disk_buffer))
  2203.                     printf("Null header\n");
  2204.                 else{
  2205.                     select_directory();
  2206.                     if(reply.good){
  2207.                         listonly=0;
  2208.                         bar_archive= command==hmUnbar;
  2209.                         fase=hack_reading;        /* per avvertire di non chiedere un disco
  2210.                                                 specifico: forse il settore 0 è danneggiato
  2211.                                                 o sovrascritto da un altro header bar
  2212.                                                 -- essentially, it's used to remember that
  2213.                                                 the floppy_n variable may be invalid,
  2214.                                                 hence when asking next disk don't rely on it */
  2215.                         if(bar_archive){
  2216.                             unbar();
  2217.                             }
  2218.                         else
  2219.                             untar();
  2220.                         print_sector_n(sect_n);
  2221.                         printf(DONE);
  2222.                         check_foreground();
  2223.                         }
  2224.                     again_command=command;
  2225.                     default_sect_n=sect_n;
  2226.                     }
  2227.                 }
  2228.             break;
  2229.         case hmMac_ize:
  2230.             if(is_wrprot()){
  2231.                 printf(mess_wrprot);
  2232.                 }
  2233.             else{
  2234.                 i=warning_first_write(1);
  2235.                 if(i>=0){
  2236.                     ioParam pb;
  2237.                     Str255 volName;
  2238.                     if(i>0){
  2239.                         ParamText(i==1?"\pNon-Mac disk":"\pEmpty Macintosh disk",
  2240.                         "\p\rAny data in this disk will be lost. Continue ?",PNS,PNS);
  2241.                         if( my_modal_dialog(139,NULL,2) == 2) break;
  2242.                         }
  2243.                     ParamText("\pVolume name :",PNS,PNS,PNS);
  2244.                     my_edt_dialog(143,volName,27,"\pUntitled");
  2245.                     printf("Creating directory...\n");
  2246.                     fillmem(disk_buffer, 0xF6, 512);
  2247.                     write_sectors(0,disk_buffer,1);
  2248.                     if(err_code)
  2249.                         check_wr_err();
  2250.                     else{
  2251.                         DIZero (drive_number,volName);
  2252.                         pb.ioVRefNum=drive_number;
  2253.                         drive_number=0;
  2254.                         PBMountVol(&pb);
  2255.                         printf(DONE);
  2256.                         }
  2257.                     invalid_buffers();
  2258.                         
  2259.                     return;
  2260.                     }
  2261.                 else{
  2262.                     diskEject();
  2263.                     return;
  2264.                     }
  2265.                 }
  2266.             break;
  2267.         case hmDriveList:
  2268.             DriveList();
  2269.             break;
  2270.         }        /* fine switch */
  2271.         command=0;
  2272.     }
  2273. }
  2274.  
  2275. short read_sect_n(n)
  2276. sector_t *n;
  2277. {
  2278. char buffer[32];
  2279. short i;
  2280. printf("sector number : ");
  2281. /* gets(buffer); */
  2282. my_itoa((long)*n,buffer);
  2283. prompt(buffer,sizeof(buffer)-1);
  2284.  
  2285. #if SECTOR_T_SIZE==4
  2286. i=my_atol(&buffer[0],n);
  2287. #else
  2288. i=my_atoi(&buffer[0],n);
  2289. #endif
  2290. if(i==0 && (*n<0 || *n >= sectors_on_floppy) ){
  2291.     printf("Invalid sector number\n");
  2292.     return -3;
  2293.     }
  2294. else if(i==-2)
  2295.     printf("Invalid digit\n");
  2296. return i;
  2297. }
  2298.  
  2299. short my_atoi(buffer,n)
  2300. register char*buffer;
  2301. register short *n;
  2302. {
  2303. for(;*buffer==' ';buffer++)
  2304.     ;
  2305. if(*buffer>='0'&&*buffer<='9'){
  2306.     *n=0;
  2307.     while(*buffer>='0'&&*buffer<='9')
  2308.             *n= *n * 10 + *buffer++ -'0';
  2309.     return 0;
  2310.     }
  2311. return *buffer? -2 : -1;
  2312. }
  2313.  
  2314. short my_atol(buffer,n)
  2315. register char*buffer;
  2316. register long *n;
  2317. {
  2318. for(;*buffer==' ';buffer++)
  2319.     ;
  2320. if(*buffer>='0'&&*buffer<='9'){
  2321.     *n=0;
  2322.     while(*buffer>='0'&&*buffer<='9')
  2323.             *n= *n * 10 + *buffer++ -'0';
  2324.     return 0;
  2325.     }
  2326. return *buffer? -2 : -1;
  2327. }
  2328.  
  2329. short untar_dec_number(buffer,doerror)
  2330. char*buffer;
  2331. short doerror;
  2332. {
  2333. short i;
  2334. if(my_atoi(buffer,&i)){
  2335.     if(doerror>=0)
  2336.         printf(in_Italia?"Testata non in formato bar !\n":
  2337.             "Error: not a bar header !\n");
  2338.     if(doerror>0)
  2339.         raise_error();
  2340.     else
  2341.         return -1;
  2342.     }
  2343.     return i;
  2344. }
  2345.  
  2346. void macize_ASCII(buf,len)
  2347. register char *buf;
  2348. register short len;
  2349. {
  2350. /* one day, it could convert also MS-DOS text, by removing any LF preceded by
  2351. a CR; but then it should have a way to return a len different than the original
  2352. value, and the static variable storing the last char of the previous call will
  2353. need to be cleared at the end of the file: too much work, and MS-DOS files
  2354. are not very common within UNIX tar archives...
  2355. */
  2356. if(len)
  2357.     do{
  2358.         if(*buf==LF) *buf=CR;
  2359.         buf++;
  2360.         }
  2361.     while(--len);
  2362. }
  2363.  
  2364. void overwrite_sectors()
  2365. {
  2366. SFTypeList    myTypes;
  2367. short charsRead;
  2368. extern char FERRORita[],FERRORing[];
  2369.  
  2370.     my_SF_Get(-1,myTypes);
  2371.     if(!reply.good) return;
  2372.  
  2373.     if(apri_file("rb",&inf_refn))
  2374.         return;
  2375.     inf_is_open=true;
  2376.     fase=writing_disk;
  2377.  
  2378.     while( (charsRead = mac_fread(disk_buffer, 512, inf_refn)) >0 ){
  2379.         if(sect_n>=sectors_on_floppy){
  2380.             printf("End of disk reached\n");
  2381.             break;
  2382.             }
  2383.         scrivi_settore(sect_n,disk_buffer);
  2384.         check_wr_err();
  2385.         sect_n++;
  2386.         check_events();
  2387.         }
  2388.     if(charsRead<0) printf(in_Italia?FERRORita:FERRORing,err_code);
  2389.  
  2390.     FSClose(inf_refn);
  2391.     inf_is_open=false;
  2392. }
  2393.  
  2394.  
  2395. void print_sector_n(sector_n)
  2396. sector_t sector_n;
  2397. {
  2398. /* well, I use a printf which does not accept a %4d descriptor... !!! */
  2399.     printf("[sector %s%ld] ",sector_n>=1000?"":sector_n>=100?" ":sector_n>=10?"  ":"   ",
  2400.         (long)sector_n);
  2401. }
  2402.  
  2403. void stampa_info_bar(n)    /* print informations from a bar volume header */
  2404. short n;
  2405. {
  2406. char buffer[16];
  2407. register short i,j;
  2408. printf("Disk number %d ", n);
  2409. for(i=j=0;i<10;i+=2,j+=3){
  2410.     buffer[j]=((barh_type*)disk_buffer)->cdate[i];
  2411.     buffer[j+1]=((barh_type*)disk_buffer)->cdate[i+1];
  2412.     }
  2413. buffer[2]=buffer[5]='/';
  2414. buffer[8]=' ';
  2415. buffer[11]=':';
  2416. buffer[14]='\0';
  2417. printf("created %s",buffer);
  2418. print_if_string("; archive name is %s",&((barh_type*)disk_buffer)->name[0],100);
  2419. printf("\n");
  2420. }
  2421.  
  2422.  
  2423. /*********************************************/
  2424.  
  2425.  
  2426. short going_to_background()
  2427. /* to write on a disk in background is very dangerous, since suntar 
  2428. uses very low level calls and can't realize that a disk was replaced 
  2429. by a Mac disk containing precious files. Hence, the user must be
  2430. alerted, and since at the next GetNextEvent I'll lose the right to get
  2431. CPU time, I can't use a standard alert
  2432. */
  2433. {
  2434.  
  2435. flush_all();    /* if the next foreground application is not MultiFinder aware,
  2436.     a lot of time (even hours) may pass before I have another chance to do
  2437.     that */
  2438. if(fase==writing_disk && sto_lavorando){
  2439.     static Rect winRect={0,0,80,300},
  2440.         boundsR1={15,0,80,300};
  2441.     WindowPtr theWindow;
  2442.     GrafPtr    savePort;
  2443.     char *p;
  2444.     unsigned long time;
  2445.  
  2446.     PositionDialog(&winRect);
  2447.     theWindow=NewWindow( NULL, &winRect, PNS, 1, dBoxProc, (WindowPtr)-1L, 0, (long)-1);
  2448.     GetPort( &savePort );
  2449.     SetPort(theWindow);
  2450.     p= in_Italia ?
  2451. "suntar continuerà a scrivere in background\rsu qualunque cosa si trovi nel drive\r\
  2452. non espellere il disco ! ! !":
  2453. "suntar will write in background\ron anything is in the disk drive\r\
  2454. please don\'t eject this disk";
  2455.  
  2456.     TextBox(p,(long)strlen(p),&boundsR1,teJustCenter);
  2457.     
  2458.     /* while(!Button()) ;
  2459.     while( Button()) ;
  2460.     FlushEvents( mDownMask|mUpMask, 0 ); */
  2461.     time=Ticks+delay_back;        /* 5 secondi (nella risorsa), ma un clic del mouse riduce l'attesa 
  2462.                         purché siano almeno 1.5 */
  2463.     while (time >Ticks)
  2464.         if(time-delay_back+90 < Ticks && Button()){
  2465.             /*FlushEvents( mDownMask, 0 );*/    /* inutile, in pratica, l'evento va al
  2466.                             processo successivo... 
  2467.                             -- a mouse click aborts the delay loop: however, I can't
  2468.                             tell the Finder that that mouse click was already served,
  2469.                             since that event is anyway passed to the application
  2470.                             which is going to foreground, I can't flush it
  2471.                             */
  2472.             break;
  2473.             }
  2474.     SetPort (savePort);
  2475.     DisposeWindow(theWindow);
  2476.     return 1;
  2477.     }
  2478. return 0;
  2479. }
  2480.  
  2481. void DriveList()
  2482. {
  2483. short i;
  2484.     disable_autoflush(2);
  2485.     one_empty_line();
  2486.     for(i=0;i<max_drive;i++){
  2487.         if(drive_type[i]){
  2488.             printf("Drive %d: ",i+1);
  2489.             switch(drive_type[i]&0xF){
  2490.             case 7:
  2491.                 printf("Hard disk 20 ");
  2492.                 break;
  2493.             case 2:
  2494.                 printf("Single sided (GCR 400k) ");
  2495.                 break;
  2496.             case 3:
  2497.                 printf("Double sided (GCR 800k) ");
  2498.                 break;
  2499.             case 4:
  2500.                 printf("SuperDrive (GCR 800k-MFM 720/1440k) ");
  2501.                 break;
  2502.             case 5:
  2503.                 {Handle h=GetResource('STR ',200);
  2504.                 if(h){
  2505.                     HLock(h);
  2506.                     printf("%P ",*h);
  2507.                     HUnlock(h);
  2508.                     break;
  2509.                     }
  2510.                 }
  2511.                 /* else unknown type */
  2512.             default:
  2513.                 printf("Unknown drive type ");
  2514.             }
  2515.             if(drive_type[i]>0){    /* that bit is set/cleared by suntar */
  2516.                 printf((drive_type[i]&0x100) ?"external":"internal");
  2517.                 if(drive_type[i]&0x200) printf("(SCSI)");
  2518.                 printf((drive_type[i]&0x400) ?", fixed (suntar can\'t open it)":", removable");
  2519.                 }
  2520.             printf("\n");
  2521.             }
  2522.         }
  2523.     printf("\n");
  2524.     enable_autoflush();
  2525. }
  2526.  
  2527. void fine_lavoro()
  2528. {
  2529. if(gInBackground)
  2530.     check_foreground();
  2531. else if(settori_passati>min_to_beep)
  2532.     SysBeep(5);
  2533. }
  2534.  
  2535. void unexpected_disk_insertion(message)
  2536. /* called when a disk is inserted and suntar does not expect a disk insertion:
  2537. obviously, that disk could be a Mac disk to be passed to the Finder, but it
  2538. could be a tar disk, or it could be in the disk drive where suntar believes
  2539. there was still the disk it has opened and on which it was working
  2540. */
  2541. long message;
  2542. {
  2543. extern Point badmount_point;
  2544. extern char *titoli[];
  2545. extern Boolean finestra_sm_aperta;
  2546. jmp_buf savebuf;
  2547. short inPlace;
  2548. Boolean andata_male;
  2549.  
  2550. sector_t old_s=sectors_on_floppy;
  2551. short old_drive_n=drive_number;
  2552. struct disk_info old_di=di;
  2553.  
  2554. mcopy(&savebuf,&main_loop,sizeof(jmp_buf));
  2555.  
  2556. andata_male=false;
  2557. drive_number=loword(message);
  2558.  
  2559. if(setjmp(main_loop)<0) {    /* at least identify_format may do a raise_error, and
  2560.     raise_error causes a bad crash if no currently running function has performed
  2561.     a setjmp, and I don't know what's the current situation */
  2562.     andata_male=true;
  2563.     }
  2564. if(andata_male || testa_stato(&inPlace,0)){
  2565.     diskEject();
  2566.     mcopy(&main_loop,&savebuf,sizeof(jmp_buf));
  2567.     sectors_on_floppy=old_s;
  2568.     drive_number=old_drive_n;
  2569.     di=old_di;
  2570.     return;
  2571.     }
  2572.  
  2573. if( (di.os==mac_HFS||di.os==mac_MFS) && (drive_number!=old_drive_n || !dirty_buffers()) ){
  2574.         /* il disco non mi riguarda, lo lascio passare
  2575.         -- that disk is of no interest to suntar; do what GetNextEvent would do,
  2576.         then what Apple suggests to do when receiving a disk insertion event */
  2577.     ParamBlockRec param;
  2578.     param.volumeParam.ioVRefNum=loword(message);
  2579.     if( (hiword(message)=PBMountVol (¶m)) != noErr ){
  2580.         DIBadMount(badmount_point, message);
  2581.         invalid_buffers();
  2582.         }
  2583.     mcopy(&main_loop,&savebuf,sizeof(jmp_buf));
  2584.     sectors_on_floppy=old_s;
  2585.     drive_number=old_drive_n;
  2586.     di=old_di;
  2587.     return;
  2588.     }
  2589.  
  2590. if(fase==non_faccio_nulla && old_drive_n==loword(message)){
  2591.     old_drive_n=0;        /* there is no reason to ask the disk back if I was
  2592.                         not working on it, simply close the old one */
  2593.     invalid_buffers();
  2594.     }
  2595.  
  2596. if( old_drive_n!=0 || file_aperto){
  2597.     if((fase==paused || fase==in_writing || fase==reading_sect_n || finestra_sm_aperta) &&
  2598.        loword(message)==old_drive_n){ /* il disco 
  2599.             era dentro, probabilmente è stato estratto a tradimento e poi reinserito 
  2600.             -- the tar disk was in that drive, probably it was ejected (without using
  2601.             suntar's eject) and inserted in back */
  2602.         if (sectors_on_floppy!=old_s ){
  2603.             if(dirty_buffers())
  2604.                 diskEject();
  2605.             else{
  2606.                 ParamBlockRec param;
  2607.                 param.volumeParam.ioVRefNum=loword(message);
  2608.                 if (di.os==unknown_os || (hiword(message)=PBMountVol (¶m)) != noErr)
  2609.                     DIBadMount(badmount_point, message);
  2610.                 }
  2611.             }
  2612.         else{
  2613.             short item;
  2614.  
  2615.             ParamText(in_Italia?"\pQuesto è il disco su cui stavo lavorando ?":
  2616.                 "\pIs this the disk I was working on ?",PNS,PNS,PNS);
  2617.             item=my_modal_dialog(139,titoli,2);
  2618.             if(item==2){
  2619.                 /*FlushVol (PNS,drive_number);*/
  2620.                 UnmountVol(NULL,drive_number);
  2621.                 diskEject();
  2622.                 }
  2623.             }
  2624.         }
  2625.     else{
  2626. /* non accetto altri dischi
  2627. -- suntar has something open and since it can't open more than one thing it can't
  2628. open that disk, do something which looks like the standard behaviour
  2629. for non-Mac or non-initialized disks
  2630. */
  2631.         if(dirty_buffers())
  2632.             diskEject();
  2633.         else if(di.os==msdos){        /* AccessPC or DOS Mounter could be installed... */
  2634.             ParamBlockRec param;
  2635.             param.volumeParam.ioVRefNum=loword(message);
  2636.             if( (hiword(message)=PBMountVol (¶m)) != noErr ){
  2637.                 DIBadMount(badmount_point, message);
  2638.                 }
  2639.             }
  2640.         else{
  2641.             diskEject();
  2642.             ParamText(in_Italia?"\pNon si possono aprire due archivi":
  2643.                 "\pCannot open more than one archive",PNS,PNS,PNS);
  2644.             my_alert();
  2645.             }
  2646.         }
  2647.     sectors_on_floppy=old_s;
  2648.     di=old_di;
  2649.     drive_number=old_drive_n;    /* diskEject lo azzera */
  2650.     }
  2651.  
  2652. else{    /* open it ! */
  2653.     if(testa_stato(&inPlace,true))        /* must call it again, for the "verbose" parameter */
  2654.         diskEject();
  2655.     else{
  2656.         if(drive_number<=last_drive && fase!=initializing){
  2657.             /*FlushVol (PNS,drive_number);*/
  2658.             /*i=*/ UnmountVol (NULL,drive_number);
  2659.             }
  2660.         if(di.os==msdos){
  2661.             ParamBlockRec param;
  2662.             param.volumeParam.ioVRefNum=drive_number;
  2663.             if( (hiword(message)=PBMountVol (¶m)) != noErr ){
  2664.                 diskEject();
  2665.                 ParamText(in_Italia?
  2666.                 "\pDisco MS-DOS, per usarlo scegli un comando \"Create…\"":
  2667.                 "\pMS-DOS disk, to open it select a \"Create…\" command",PNS,PNS,PNS);
  2668.                 my_alert();
  2669.                 }
  2670.             drive_number=0;
  2671.             }
  2672.         else if(!di.is_not_initialized)
  2673.             (void)identify_format();
  2674.         }
  2675.     }
  2676. mcopy(&main_loop,&savebuf,sizeof(jmp_buf));
  2677. }
  2678.  
  2679. /************** gestione menù ****************/
  2680.  
  2681. static void EnableDisableItem(menu, item, flag)
  2682. MenuHandle menu;
  2683. short item;
  2684. Boolean flag;
  2685. {
  2686. if(flag)
  2687.     EnableItem(menu, item);
  2688. else
  2689.     DisableItem(menu, item);
  2690. }
  2691.  
  2692. void MaintainApplSpecificMenus()
  2693. /* it's an idea borrowed from TEsample: rather than enabling and disabling
  2694. items when the situation changes, be sure that some global variables always
  2695. tell what the situation is and adjust all the menu items when receiving a 
  2696. keyDown event with the Command key or a MouseDown event in the menu bar.
  2697.  That's the most reasonable way to do things in a program which has an abort
  2698. command and does not quit at the first error.
  2699. */
  2700. extern Boolean finestra_sm_aperta;
  2701. extern DialogPtr ListDialog;
  2702.  
  2703. Boolean b;
  2704. b= fase==non_faccio_nulla;
  2705. if(b){
  2706.     EnableDisableItem(myMenus[fileM], fmGetInfo, !file_aperto&&drive_number==0);
  2707.     EnableDisableItem(myMenus[fileM], fmCopy, !file_aperto);
  2708.     EnableItem(myMenus[fileM], fmList);
  2709.     EnableItem(myMenus[fileM], fmExtract);
  2710.     EnableDisableItem(myMenus[fileM], fmWriteTar, !file_aperto);
  2711.     EnableDisableItem(myMenus[fileM], fmWriteBar, !file_aperto);
  2712.     EnableDisableItem(myMenus[fileM], fmAppend, !file_aperto);
  2713.     EnableDisableItem(myMenus[fileM], fmFormat, !file_aperto);
  2714.     EnableItem(myMenus[fileM], fmSelect);
  2715.     }
  2716. else{
  2717.     DisableItem(myMenus[fileM], fmGetInfo);
  2718.     DisableItem(myMenus[fileM], fmCopy);
  2719.     DisableItem(myMenus[fileM], fmList);
  2720.     DisableItem(myMenus[fileM], fmExtract);
  2721.     DisableItem(myMenus[fileM], fmWriteTar);
  2722.     DisableItem(myMenus[fileM], fmWriteBar);
  2723.     DisableItem(myMenus[fileM], fmAppend);
  2724.     DisableItem(myMenus[fileM], fmFormat);
  2725.     EnableDisableItem(myMenus[fileM], fmSelect, ListDialog&&FrontWindow()!=ListDialog);
  2726.     }
  2727. /* il Think C marker non accetta macro su due righe, e non voglio perdere i suoi servizi ! */
  2728. #define abort_mask    ( (1<<writing_disk) | (1<<reading_disk) | (1<<reading_sect_n) | (1<<hack_reading) | (1<<hack_listing) | (1<<paused) | (1<<in_writing) | (1<<selected_reading) )
  2729.  
  2730. EnableDisableItem(myMenus[fileM], fmPause, pausable || fase==paused /* nel secondo
  2731.             caso, l'item è diventato resume */ || finestra_sm_aperta&&((abort_mask>>fase)&1));
  2732. EnableDisableItem(myMenus[fileM], fmOpen, fase==non_faccio_nulla&&drive_number==0&&!file_aperto);
  2733.  
  2734. #ifdef V_122
  2735. EnableDisableItem(myMenus[fileM], fmEject, drive_number!=0 &&( fase==non_faccio_nulla || fase==in_writing
  2736.     /* || fase==paused || finestra_sm_aperta*/) );        /* sarebbe sensato averlo attivo
  2737.                 anche allora, ma non passo dal main per gestirlo ! */
  2738. EnableDisableItem(myMenus[fileM], fmClose, fase==non_faccio_nulla&&file_aperto);
  2739. #else
  2740. /* in the 1.3 version, they share the same item */
  2741. {
  2742. unsigned char itemname[32];
  2743. short i=2;
  2744. if(!file_aperto&&drive_number==0)
  2745.     DisableItem(myMenus[fileM], fmEject);
  2746. else{
  2747.     if(file_aperto)
  2748.         i=1;
  2749.     EnableDisableItem(myMenus[fileM], fmClose, fase==non_faccio_nulla || fase==in_writing);
  2750.     }
  2751. GetIndString (itemname,129,i);
  2752. SetItem (myMenus[fileM],fmClose,itemname);
  2753. }
  2754. #endif
  2755.  
  2756.  
  2757. /*EnableDisableItem(myMenus[fileM], fmAbort, fase==writing_disk ||fase==reading_disk ||
  2758.     fase==reading_sect_n || fase==hack_reading || fase==hack_listing || fase==paused) || 
  2759.     fase==in_writing || fase==selected_reading; */
  2760. EnableDisableItem(myMenus[fileM], fmAbort, (abort_mask>>fase)&1 );
  2761.  
  2762. if(expert_mode){
  2763.     if(b){
  2764.         EnableItem(hackersMenu, hmView);
  2765.         EnableDisableItem(hackersMenu, hmClear,!file_aperto);
  2766.         EnableDisableItem(hackersMenu, hmMac_ize,!file_aperto);
  2767.         EnableDisableItem(hackersMenu, hmOverwrite,!file_aperto);
  2768.         EnableItem(hackersMenu, hmSave);
  2769.         EnableItem(hackersMenu, hmFind);
  2770.         EnableItem(hackersMenu, hmUntar);
  2771.         EnableItem(hackersMenu, hmUnbar);
  2772.         EnableItem(hackersMenu, hmList);
  2773.         EnableItem(hackersMenu, hmDriveList);
  2774.         EnableDisableItem(hackersMenu, hmAgain, again_command!=0);
  2775.         }
  2776.     else{
  2777.         DisableItem(hackersMenu, hmView);
  2778.         DisableItem(hackersMenu, hmClear);
  2779.         DisableItem(hackersMenu, hmMac_ize);
  2780.         DisableItem(hackersMenu, hmOverwrite);
  2781.         DisableItem(hackersMenu, hmSave);
  2782.         DisableItem(hackersMenu, hmFind);
  2783.         DisableItem(hackersMenu, hmUntar);
  2784.         DisableItem(hackersMenu, hmUnbar);
  2785.         DisableItem(hackersMenu, hmList);
  2786.         DisableItem(hackersMenu, hmDriveList);
  2787.         DisableItem(hackersMenu, hmAgain);
  2788.         }
  2789.     }
  2790. }
  2791.  
  2792.  
  2793. void set_skip_all(n)
  2794. short n;
  2795. {
  2796. /* il confirm saves ha tre stati: 
  2797.     non selezionato (confirm_saves=0,saveskip_all=0)
  2798.     selezionato     (confirm_saves=1,saveskip_all=0)
  2799.     posto in corsivo da una skip all o save all (confirm_saves=0,saveskip_all=1)
  2800. questa routine gestisce i passaggi tra i tre stati:
  2801.  
  2802. n= 0 -> se è in corsivo torna sel, se no resta immutato;
  2803. n= 1 -> da sel commuta a posto in corsivo (e da non sel resta immutato !)
  2804. n=-1 -> da chiamare quando seleziono l'entry del menù: se è in corsivo torna selezionato,
  2805.         se no inverte lo stato attuale
  2806.  
  2807. -- the confirm saves menu item has three states:
  2808.     non-selected (confirm_saves=0,saveskip_all=0)
  2809.     selected     (confirm_saves=1,saveskip_all=0)
  2810.     italicized by a skip all or save all (confirm_saves=0,saveskip_all=1)
  2811. this routine handles all its status changes:
  2812. n=0 => I'm in the main loop, if it's italicized then make it selected
  2813.   1 => the save all or skip all was clicked (caution, the confirm saves could 
  2814.         have been disabled after the window appeared, and the button may still
  2815.         be clicked)
  2816.  -1 => the confirm saves menu item was selected: if italicized return normal,
  2817.         otherwise invert its current state
  2818.  
  2819. */
  2820. static Boolean saveskip_all=false;
  2821.  
  2822. if(!n || (n<0&&saveskip_all) ){
  2823.     if(saveskip_all){
  2824.         saveskip_all=false;
  2825.         SetItemStyle(myMenus[prefM],pmConfirm,0);
  2826.         confirm_saves=true;
  2827.         }
  2828.     }
  2829. else if (n>0){
  2830.     if(confirm_saves||saveskip_all){    /* può capitare che non sia così se 
  2831.             deseleziono durante il dialogo e poi clicco su un bottone...*/
  2832.         saveskip_all=true;
  2833.         SetItemStyle(myMenus[prefM],pmConfirm, 2);    /* corsivo */
  2834.         confirm_saves=false;
  2835.         }
  2836.     }
  2837. else{    /* n=-1, saveskip_all=0 */
  2838.     CheckItem(myMenus[prefM],pmConfirm,confirm_saves^=1);
  2839.     }
  2840. }
  2841.  
  2842. void load_OSType(short,OSType *);
  2843. static void load_OSType(id,dest)
  2844. short id;
  2845. OSType *dest;
  2846. {
  2847. Handle h;
  2848. if((h=GetResource ('STR ',id))==NULL)
  2849.     *dest='????';
  2850. else{
  2851.     HLock(h);
  2852.     mcopy((char*)dest,(char*)*h+1,4);
  2853.     ReleaseResource(h);
  2854.     /* *dest = (((long)*(unsigned char*)(*h+1))<<24) +
  2855.                   (((long)*(unsigned char*)(*h+2))<<16) +
  2856.                   (((long)*(unsigned char*)(*h+3))<<8) +
  2857.                   ((long)*(unsigned char*)(*h+4));    */
  2858.     }
  2859. }
  2860.  
  2861. long load_number(short,short);
  2862. static long load_number(id,deflt)
  2863. short id;
  2864. short deflt;
  2865. {
  2866. Handle h;
  2867. if((h=GetResource ('STR ',id))==NULL)
  2868.     return deflt;
  2869. else{
  2870.     long temp;
  2871.     HLock(h);
  2872.     temp=pstrtoi(*h);
  2873.     ReleaseResource(h);
  2874.     return temp;
  2875.     }
  2876. }
  2877.  
  2878. void prefs_da_risorsa()
  2879. /* read all the preference settings which depend on a resource, including
  2880. the INTL 0 resorce which is in the System file and contains the code
  2881. for the nation, and compute the centered locations for those dialogs which
  2882. are difficultly moved after their creation
  2883. */
  2884. {
  2885. Handle h;
  2886. short i;
  2887. static Rect bmr={0,0,96,300};
  2888. static short SF_IDs[]={199,200,-3999,-4000,1043,400,399};
  2889. extern long my_uid,my_gid;
  2890. extern char *uname,*gname;
  2891. extern Boolean gHasCustomPutFile,SB3_compatibility;
  2892. extern char *printf_buf;
  2893. #define verItSwiss 36
  2894.  
  2895. load_OSType(129,&tar_creator);
  2896. load_OSType(136,&bar_creator);
  2897. load_OSType(137,&bar_type);
  2898.  
  2899. max_hqx_header=load_number(134,10240);
  2900.  
  2901. my_uid=load_number(130,0);
  2902. my_gid=load_number(131,0);
  2903. list_buf_size=load_number(142,128);
  2904. printf_buf=NewPtr((Size)list_buf_size);
  2905.  
  2906. uname=gname="";
  2907. ResrvMem ((Size)64);
  2908. h=GetResource ('STR ',132);
  2909. if(h){
  2910.     HLock(h);
  2911.     uname=my_p2cstr(*h);
  2912.     }
  2913. h=GetResource ('STR ',133);
  2914. if(h){
  2915.     HLock(h);
  2916.     gname=my_p2cstr(*h);
  2917.     }
  2918.  
  2919. if((h=GetResource ('STR ',135))!=NULL ){
  2920.     if(**h){
  2921.         char c= *(*h+1)&~0x20;
  2922.         if(c=='I')
  2923.             in_Italia=true;
  2924.         else if(c=='E')
  2925.             in_Italia=false;
  2926.         else
  2927.             h=NULL;
  2928.         }
  2929.     else
  2930.         h=NULL;
  2931.     }
  2932.  
  2933. #ifdef THINK_C_5
  2934. #define Intl0Vers intl0Vers
  2935. #endif
  2936. if(h==NULL){
  2937.     h=IUGetIntl (0);
  2938.     if(h!=NULL){
  2939.         in_Italia=(((Intl0Rec*)*h)->Intl0Vers>>8)==verItaly || 
  2940.             (((Intl0Rec*)*h)->Intl0Vers>>8)==verItSwiss;
  2941.         ReleaseResource(h);
  2942.         CheckItem(myMenus[prefM],pmEnglish,!in_Italia);
  2943.         }
  2944.     }
  2945.  
  2946. h=GetResource ('STR ',141);
  2947. if(h && **h && ((*h)[1] | 0x20)!='n') SB3_compatibility=true;
  2948.  
  2949. floppy_buffer_size =load_number(138,18);
  2950. hd_buffer_size = load_number(139,20)<<9;
  2951. back_prio = load_number(140,4);
  2952.  
  2953. load_options();
  2954.  
  2955. /* compute the centered position for the the disk initialization dialog */
  2956. PositionDialog(&bmr);        /* finestra usata da DIBadMount, uso dimensioni fisse 
  2957.             che però sono quelle della finestra personalizzata e dovrebbero coincidere
  2958.             con quelle di sistema */
  2959. *(long*)&badmount_point=*(long*)&bmr;
  2960. /* sotto il System 7 passare {0,0} allo standard file provoca un dialogo 
  2961. centrato, ma purtroppo col system 6 non è così... */
  2962.  
  2963. /* and the positions for the standard file dialogs */
  2964. for(i=0;i<sizeof(SF_IDs)/sizeof(short);i++){
  2965.     AlertTHndl    alertHandle = (AlertTHndl)GetResource('DLOG',SF_IDs[i]);
  2966.     if(alertHandle){
  2967.         PositionDialog( &((**alertHandle).boundsRect));
  2968.         where[i]=*(Point*)&((**alertHandle).boundsRect);
  2969.         }
  2970.     else{
  2971.         static Point    def_where={80,80};
  2972.         where[i]=def_where;
  2973.         }
  2974.     }
  2975. }
  2976.  
  2977. void load_options()
  2978. {
  2979. static OSType gif_default='QGif';
  2980. Handle h;
  2981. if((h=GetResource ('OPTs',128))==NULL){
  2982.     /* create the options resource if it doesn't exist: probably that will not
  2983.     be useful to the user, we'll make suntar 1.2 and 1.3 available with an OPTs
  2984.     resource (otherwise, a file which grows could make somebody think about
  2985.     viruses) but during the development of the program it was useful,
  2986.     each time we changed the format of the resource, deleting the old one
  2987.     one obtains the creation of the new one */
  2988.     h=NewHandle(sizeof(options));
  2989.     fillmem(&options,0,sizeof(options));
  2990.     text_creator='EDIT';
  2991.     gif_creator=gif_default;
  2992.     resolve_aliases=useSys7_SF=true;
  2993.     non_text_ASCII=1;
  2994.     smallFilesAreASCII=1;
  2995.     delay_back=300;
  2996.     min_to_beep=500;
  2997.     del_incompl=true;
  2998.     mcopy(*h,&options,sizeof(options));
  2999.     AddResource (h, 'OPTs',128,PNS);
  3000.     WriteResource(h);
  3001.     }
  3002. else{
  3003.     Size s=GetHandleSize(h);
  3004.     if(s<sizeof(options)){        /* somebody is using the old format of the OPTs
  3005.                                 resource (that of 1.2), convert it to the new format:
  3006.                                 it's always wise to support old formats for
  3007.                                 anything */
  3008.         SetHandleSize (h,(Size)sizeof(options));
  3009.         fillmem(*h+(&options.opt_bytes[12]-(char*)&options),0,8);
  3010.         *(char*)(*h+(&options.opt_bytes[12]-(char*)&options)) = 1;
  3011.         mcopy(*h+((char*)&options.gif_cr-(char*)&options),&gif_default,4);
  3012.         *( *h+(&options.opt_bytes[0]-(char*)&options) ) <<= 1;    /* it's no more a Boolean... */
  3013.         ChangedResource(h);
  3014.         WriteResource(h);
  3015.         }
  3016.     mcopy(&options,*h,sizeof(options));
  3017.     }
  3018. ReleaseResource(h);
  3019. }
  3020.  
  3021. void save_options()
  3022. {
  3023. Handle h;
  3024. h=GetResource ('OPTs',128);
  3025. mcopy(*h,&options,sizeof(options));
  3026. ChangedResource(h);
  3027. WriteResource(h);
  3028. ReleaseResource(h);
  3029. }
  3030.  
  3031. void add_expert_menu(void);
  3032. static void add_expert_menu()
  3033. {
  3034. unsigned char itemname[48];
  3035.     GetIndString(itemname,130,1);
  3036.     AppendMenu(myMenus[prefM],itemname);
  3037.     GetIndString(itemname,130,2);
  3038.     AppendMenu(myMenus[prefM],itemname);
  3039.     InsertMenu(hackersMenu = GetMenu(hackID),0);
  3040. }
  3041.  
  3042.  
  3043. static void add_menu()    /* create application specific menus */
  3044. {
  3045. short markChar;
  3046.  
  3047.     CheckItem(myMenus[prefM],pmAutowrap,false);
  3048.     CheckItem(myMenus[prefM],pmConfirm,false);
  3049.     GetItemMark (hqxM,bmDisable,&markChar);
  3050.     disable_binhex = markChar==checkMark;
  3051.     GetItemMark (hqxM,bmShowExtr,&markChar);
  3052.     if(markChar==checkMark) disable_binhex |=2;
  3053.     GetItemMark (hqxM,bmSaveInfo,&markChar);
  3054.     if(markChar==checkMark) disable_binhex |=8;
  3055.     GetItemMark (hqxM,bmShowList,&markChar);
  3056.     if(markChar==checkMark) disable_binhex |=4;
  3057.  
  3058. #ifdef V_122
  3059.     GetItemMark (myMenus[prefM],pmSmallText,&markChar);
  3060.     smallFilesAreASCII= markChar==checkMark;
  3061. #endif
  3062.     GetItemMark (myMenus[prefM],pmExpert,&markChar);
  3063.     expert_mode= markChar==checkMark;
  3064.     InsertMenu(writeMenu = GetMenu(writeID), 0);
  3065.     DisableItem(writeMenu, 0);
  3066.     if(expert_mode) add_expert_menu();    /* always un-checked... */
  3067.     tarPopupMenu = GetMenu(tarPopupID);
  3068.     ntAPopupMenu = GetMenu(ntAPopupID);
  3069.  
  3070. }
  3071.  
  3072. static void handle_menus(choice)    /* handle application specific menus */
  3073. long choice;
  3074. {
  3075. if(hiword(choice)==appleID)
  3076.     about_box();
  3077. else if(hiword(choice)==prefID)
  3078.     switch(loword(choice)) {
  3079.     case pmOptions:
  3080.         flush_all();
  3081.         options_box();
  3082.         break;
  3083.     case pmEnglish:{
  3084.         short markChar;
  3085.         in_Italia^=1;
  3086.         GetItemMark (myMenus[prefM],pmEnglish,&markChar);
  3087.         CheckItem(myMenus[prefM],pmEnglish,!markChar);
  3088.         }
  3089.         break;
  3090.     case pmConfirm:
  3091.         set_skip_all(-1);
  3092.         break;
  3093. #ifdef V_122
  3094.     case pmSmallText:
  3095.         CheckItem(myMenus[prefM],pmSmallText, smallFilesAreASCII^=1);
  3096.         preferences_changed=true;
  3097.         break;
  3098. #endif
  3099.     case pmExpert:
  3100.         CheckItem(myMenus[prefM],pmExpert,expert_mode ^=1);
  3101.         if(expert_mode){
  3102.             add_expert_menu();
  3103.             }
  3104.         else{
  3105.             DelMenuItem (myMenus[prefM], pmNoConvers);
  3106.             DelMenuItem (myMenus[prefM], pmIgnore);
  3107.             DeleteMenu (hackID);
  3108.             ignore_errors=non_convertire=false;
  3109.             }
  3110.         DrawMenuBar();
  3111.         preferences_changed=true;
  3112.         break;
  3113.     case pmIgnore:
  3114.         CheckItem(myMenus[prefM],pmIgnore,ignore_errors^=1);
  3115.         break;
  3116.     case pmNoConvers:
  3117.         CheckItem(myMenus[prefM],pmNoConvers,non_convertire^=1);
  3118.         break;
  3119.     }
  3120. else if(hiword(choice)==hqxID){
  3121.     preferences_changed=true;
  3122.     switch(loword(choice)){
  3123.     case bmDisable:
  3124.         CheckItem(hqxM,bmDisable,(disable_binhex^=1)&1);
  3125.         break;
  3126.     case bmShowExtr:
  3127.         CheckItem(hqxM,bmShowExtr,((disable_binhex^=2)&2)!=0);
  3128.         break;
  3129.     case bmSaveInfo:
  3130.         CheckItem(hqxM,bmSaveInfo,((disable_binhex^=8)&8)!=0);
  3131.         break;
  3132.     case bmShowList:
  3133.         CheckItem(hqxM,bmShowList,((disable_binhex^=4)&4)!=0);
  3134.         break;
  3135.     }
  3136.     }
  3137. else{    /* fileID o writeID oppure hackID, tanto non sono mai abilitati insieme, 
  3138.         e comunque non butto via l'informazione
  3139.         -- I don't serve the command, rather I remember that it was selected.
  3140.         That's a matter of program hierarchy: MainEvent is a slave, it's not the
  3141.         master, hence important operations are not executed under it, and
  3142.         this routine is called from it.
  3143.         */
  3144.  
  3145.     if(choice==menuItemMess(fileID,fmSelect)&&ListDialog&&
  3146.         ListDialog != FrontWindow() ){
  3147.         SelectWindow(ListDialog);
  3148.         }
  3149.     else
  3150.         last_selection= choice;
  3151.     }
  3152. }
  3153.  
  3154. static short dialogo_abort()
  3155. {
  3156.     ParamText(in_Italia?"\pVuoi interrompere il comando in corso ?":
  3157.         "\pDo you want to abort the current command and quit ?",PNS,PNS,PNS);
  3158.     beep_in_foreground();
  3159.     return my_modal_dialog(139,titoli,2);
  3160. }
  3161.  
  3162.  
  3163. static short my_quit_handler()
  3164. {
  3165.  
  3166. if(((abort_mask>>fase)&1) && fase!=in_writing){    /* it's the condition used for the abort menu item */
  3167.     if(dialogo_abort()==2) return 0;
  3168.     }
  3169.  
  3170. check_and_eject();    /* ejects the disk and, if writing, flushes and truncates... */
  3171.  
  3172. if(!preferences_changed) return 1;
  3173.  
  3174. /* save the preferences settings */
  3175. if(expert_mode){
  3176.     DelMenuItem (myMenus[prefM], pmNoConvers);
  3177.     DelMenuItem (myMenus[prefM], pmIgnore);
  3178.     }
  3179. (**myMenus[prefM]).menuProc=NULL;    /* without it, horrible things happen */
  3180. ChangedResource(myMenus[prefM]);
  3181. WriteResource(myMenus[prefM]);
  3182.  
  3183. (**hqxM).menuProc=NULL;
  3184. ChangedResource(hqxM);
  3185. WriteResource(hqxM);
  3186.  
  3187. close_or_del_out_file();    /* ExitToShell closes all files, but obviously does not
  3188.                 flush my internal buffer nor delete incomplete files if that
  3189.                 option is checked */
  3190.  
  3191. return 1;
  3192. }
  3193.  
  3194. /******************/
  3195.  
  3196. void print_chars(p,n)
  3197. char* p;
  3198. short n;
  3199. {
  3200. if(!n) return;
  3201. while(--n)
  3202.     put_char(*p++);
  3203. printf("%c",*p);    /* to flush the buffer and update the scrollbars */
  3204. }
  3205.  
  3206. void flush_all()
  3207. {
  3208. if(dirty_buffers()) flush_buffers();
  3209. flush_console();
  3210. }
  3211.